import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
import javax.microedition.rms.*;
import java.util.*;

//#if Nokia && !MIDP2
   import com.nokia.mid.ui.*;
//#endif

//#if SOUND_NOKIA_RT
   import com.nokia.mid.sound.*;
//#elif SOUND_MMAPI
   import javax.microedition.media.*;
//#elif SAMSUNG_MMF
   import com.samsung.util.*;
//#elif SHARP_MMF
   import com.vodafone.v10.sound.*;
//#endif

public class GameScreen 
   //#if Nokia && !MIDP2
      extends FullCanvas 
   //#else
      extends Canvas 
   //#endif
   implements Runnable, Constants
   //#if SOUND_NOKIA_RT
      , SoundListener
   //#elif SOUND_MMAPI
      , PlayerListener
   //#endif
   //#if !FULL_CANVAS
      , CommandListener
   //#endif
{
   //#if Nokia && (S30 || S40v1 || S40v2 || N6235)
      private long timeNextSetLights;
   //#endif

   private volatile Thread thread;
   private Thread curThread;
   static SpaceRacer midlet;

   public static Graphics gd;

   private boolean keyIsPressed, keyIsReleased, isPainting, noteVisible, isGasKeyPressing, isGasKeyReleasing, flag,
                   cheat_AllLevels;

   public static boolean cheat_Shield, cheat_Nitro, cheat_Missiles, cheat_Bomb, cheat_Mine;

   public static int  screenWidth, screenHeight, fontHeight;

   private long timeStartLoop, timeStartPause, currentRealTime, currentVirtualTime, lastVirtualTime, timeSchduledTask, progress;
   public static long timeStartGame, levelTime, levelTotalTime, cheatCode;

   private int gameState, gameSubState, gameMode, roadState,
               tfeRepetition, tfePosY, tceRepetition,
               keyCode, keyReleasedCode,
               posX, posY,
               worldStepX, worldStepY,
               trackCurrentRow, trackCountElements, firstTrackItem,
               textPosX, textPosY, textWidth, textHeight, textCountRow, textFirstRow, textLastRow, textStrIndex,
               editorCountChars, editorCurrentChar, editorCurRow, editorCurCol,
               levelBonusTime, levelScores, levelBonus, levelTotalScores, levelResultScores, levelTotalResultScores,
               shipBodyState,
               place,
               controlSelectedItem,
               ssCurrentShip, ssCurrentShipPosX, ssCurrentShipWidth, ssOldShip, ssOldShipPosX, ssOldShipWidth, ssStep, ssShipAreaX1, ssShipAreaY1, ssShipAreaX2, ssShipAreaY2;
   
   private byte levelResult, 
                groupsCount, levelsCount,
                connectionState,
                textFormat;

   public static int explosionFirstFreeIndex, shotFirstFreeIndex,
                     worldPosX, worldPosY, worldLength, trackOffSetY, trackLength,
                     minShipPosY, maxShipPosY,
                     groupTotalCount, groupCurrent, levelCurrent, shipCurrent;

   private static StringBuffer timeStr, tempResStr, tempStr, gameSession, groupHash;
   private Timer timer;
   private Menu menu;

   public static byte[] settings, passedLevels, control;

   private char[][] editorChars;
   private char[] editorStr;

   static byte[] charOffset;

   private int[] binSpecs;

   private byte[] imgQueue;
   public static Image[] images;
   private Image imgLaser, imgSensor;

   private Animation ssCurrentShipAnim, ssOldShipAnim;
      // Array for queue of strings
   //   -1 - empty
   //    1 = string is in the queue for loading
   private byte[] strQueue;
   public static StringBuffer[] strings, text;
    public StringBuffer[] user;
    public short[] strWidth, textRowWidth;

   static private LevelData[] rmsLevelData;
   static private LevelData[][] jarLevelData;
   static private GroupData[] groups;

   private TElement[] track;
   public static Border[] borders;
   public static long[] cos, sin;
   public static WayPoint[][] wayPoints;
   public static byte[] npcBehavior, npcType;
   public static TrackItems[] trackItems;

   //#if Galaxy
      // 0xFF000000 - star's type (index)
      // 0x00FFF000 - posX
      // 0x00000FFF - posY
      private int[] stars;
      private int starsStepX, starsOffSetX, starsStepY, starsOffSetY;
   //#endif
   
   private Ship ship;
   private NPC[] npcShips;

   public static Explosion[] explosions;
   public static Shot[] shots;

   private static InputStream in;
   public static DataInputStream din;
   public  static ByteArrayOutputStream baos;
   private static DataOutputStream out;
   private static RecordStore rst;
  
   //#if mp
   private static HttpConnection httpConn;
   public static int httpContentLength;
   //#endif

   private static Random rnd;

   //#if SOUND_NOKIA_RT
      private static Sound[] sounds;
      private static byte soundState;
      private static byte soundId;
   //#elif SOUND_MMAPI
      private static Player[] soundPlayer;
      private static byte soundId;
   //#elif SAMSUNG_MMF
      private static AudioClip[] soundPlayer;
      private static byte soundId;
   //#elif SHARP_MMF
      public static SoundPlayer soundPlayer;
      private static Sound[] soundData;
      private static SoundTrack[] soundTracks;
   //#endif

   //#if sp
      private String[] top10Name;
      private int[] top10Score;
      private int top10count;
   //#endif


/******************************************************************************/

   //#if MIDP2
   protected void sizeChanged(int w,int h)
   {
      screenWidth = w;
      screenHeight = h;
   }
   //#endif

/******************************************************************************/

//#if !FULL_CANVAS
   public static Command cmdLeft  = null;
   public static Command cmdRight = null;
   public static Command cmdBack  = null;

   public void commandAction(Command cmd, Displayable d)
   {
      if(cmd == cmdLeft)
      {
         keyPressed(KEYS[KEY_SELECT]);
      }
      if(cmd == cmdRight || cmd == cmdBack)
      {
         keyPressed(KEYS[KEY_CANCEL]);
      }

   }

   public String getLabelCmd(Command cmd)
   {
      if(cmd != null) return cmd.getLabel();
      return "";
   }

   public void addCmd(int keys, StringBuffer label)
   {
      if(keys == KEY_SELECT)
      {
         cmdLeft = new Command(label.toString(), Command.OK, 1);
         addCommand(cmdLeft);
      }
      if(keys == KEY_CANCEL)
      {
         cmdBack = new Command(label.toString(), Command.BACK, 1);
         addCommand(cmdBack);
         cmdRight = new Command(label.toString(), Command.CANCEL, 1);
         addCommand(cmdRight);
      }
   }

   public void removeAllCmds()
   {
      if(cmdLeft != null)
      {  
         removeCommand(cmdLeft);
      }
      if(cmdRight != null)
      {  
         removeCommand(cmdRight);
      }
      if(cmdBack != null)
      {  
         removeCommand(cmdBack);
      }
      cmdLeft = null;
      cmdRight = null;
      cmdBack = null;
   }
//#endif

/******************************************************************************/
  
   public GameScreen(SpaceRacer midlet) 
   {
      int i, j, tInt;

      thread = null;
      curThread = null;
      this.midlet = midlet;

      //#if MIDP2
         setFullScreenMode(true);
      //#endif
    
      //#if !FULL_CANVAS
         setCommandListener(this);
      //#endif

      //#if Nokia && (S30 || S40v1 || S40v2 || N6235)
         timeNextSetLights = System.currentTimeMillis() + SETLIGHTS_TIME;
      //#endif

      fontHeight = HChar;
      screenWidth = getWidth();
      screenHeight = getHeight();

      keyIsPressed = false;
      keyIsReleased = false;

      cheat_AllLevels = false;

      gameSession = new StringBuffer(GAME_SESSION_LENGTH);
      timeStr = new StringBuffer(8);
      tempResStr = new StringBuffer(60);
      tempStr = new StringBuffer(20);

      groupHash = new StringBuffer(GROUP_HASH_LENGTH);

      user = new StringBuffer[2];
      user[USER_NAME] = new StringBuffer(EDITOR_NAME_LENGTH);
      user[USER_ID] = new StringBuffer(32);
      userRead();

      timer = new Timer();

      charOffset = new byte[WChar.length - 1];
      for(i = 0; i < FONT_ROW_COUNT; i++)
      {
        tInt = 0;
        for(j = 0; j < charOffset.length; j++)
        {
          if(RowInImg[j + 1] == i)
          {
            charOffset[j] = (byte)tInt;
            tInt += WChar[j + 1];
          }
        }
      }

      settings = new byte[7];
      settings[SETTINGS_DL_INF]       = 0;
      settings[SETTINGS_DL_SPECS]     = 0;
      settings[SETTINGS_DL_BIN]       = 0;
      settings[SETTINGS_GROUP]        = 0; 
      settings[SETTINGS_LEVEL]        = 0; 
      settings[SETTINGS_COUNT_LEVELS] = 50;
      settings[SETTINGS_SOUND]        = 1;
      if(!readSettings(settings, RMS_SETTINGS)) writeSettings(settings, RMS_SETTINGS);

      control = new byte[CONTROL_COUNT];
      control[CONTROL_POWER_UP]   = KEYS[KEY_NUM_2];
      control[CONTROL_TURN_LEFT]  = KEYS[KEY_NUM_4];
      control[CONTROL_TURN_RIGHT] = KEYS[KEY_NUM_6];
      control[CONTROL_UP_LEFT]    = KEYS[KEY_NUM_1];
      control[CONTROL_UP_RIGHT]   = KEYS[KEY_NUM_3];
      control[CONTROL_BRAKE]      = KEYS[KEY_NUM_0];
      control[CONTROL_USE_ITEM]   = KEYS[KEY_NUM_5];
      if(!readSettings(control, RMS_CONTROL)) writeSettings(control, RMS_CONTROL);

      passedLevels = new byte[settings[SETTINGS_COUNT_LEVELS]];
      
      strQueue = new byte[STR_COUNT];
      strings = new StringBuffer[STR_COUNT];
      strWidth = new short[STR_COUNT];
      strClear();
      
      //#if SOUND_NOKIA_RT
         sounds = new Sound[SOUND_COUNT];
      //#elif SOUND_MMAPI
         soundPlayer = new Player[SOUND_COUNT];
      //#elif SAMSUNG_MMF
         soundPlayer = new AudioClip[SOUND_COUNT];
      //#elif SHARP_MMF
         try{
            soundPlayer = SoundPlayer.getPlayer();
         } 
         catch (Exception e) 
         {
            //e.printStackTrace();
         }
         soundData = new Sound[SOUND_COUNT];
         soundTracks = new SoundTrack[SOUND_COUNT];
      //#endif

      binSpecs = new int[BIN_COUNT_TOTAL_ITEMS];
      for(i = BIN_COUNT_TRACK_ITEMS, j = 0; j < BIN_SPECS.length; i++, j++)
      {
         binSpecs[i] = BIN_SPECS[j];
      }

      imgQueue = new byte[IMG_COUNT];
      images = new Image[IMG_COUNT];
      imgClear();

      menu = new Menu(this);

      //#if sp
         top10Name = new String[10];
         top10Score = new int[10];
         top10count = 0;
         top10ReadRMS();
      //#endif
   }


   public void init()
   {
      imgRequest(IMG_LOGO);
      initIntro();

      //#if !FULL_CANVAS
         removeAllCmds();
      //#endif

      timer.set(3000);
      gameState = GS_LOGO;

      groupCurrent = 0;
      levelCurrent = 0;
      shipCurrent = 0;
   }

   public void startUp()
   {
      Display.getDisplay(midlet).setCurrent(this);
      start();

   }

/**************************************************************************************************/

   private byte getKeyName(byte key)
   {
      for(int i = 0; i < KEYS.length; i++)
      {
         if(key == KEYS[i]) return KEY_NAMES[i];
      }
      return -1;
   }

   private boolean isKeyFree(int key, int controlIndex)
   {
      for(int i = 0; i < control.length; i++)
      {
         if(key == control[i] && i != controlIndex) return false;
      }
      if((key == KEYS[KEY_UP]    && controlIndex != CONTROL_POWER_UP) ||
         (key == KEYS[KEY_DOWN]  && controlIndex != CONTROL_BRAKE) ||
         (key == KEYS[KEY_LEFT]  && controlIndex != CONTROL_TURN_LEFT) ||
         (key == KEYS[KEY_RIGHT] && controlIndex != CONTROL_TURN_RIGHT) ||
         (key == KEYS[KEY_FIRE]  && controlIndex != CONTROL_USE_ITEM)) return false;
      return true;
   }

/**************************************************************************************************/

/**************************************************************************************************/
/***                                                                                             **/
/***                          Functions for working with settings                                **/
/***                                                                                             **/
/**************************************************************************************************/

   private boolean readSettings(byte[] data, String rmsName)
   {
      boolean flag = false;
      int i;

      try{
         if(openDataInputStream(rmsRead(rmsName)))
         {
            for(i = 0; i < data.length; i++)
            {
               data[i] = (byte)dinRead();
            }
            flag = true;
         }
      }
      catch(Exception ex)
      { 
         //ex.printStackTrace(); 
      }
      inClose();
      return flag;
   }


   private void writeSettings(byte[] data, String rmsName)
   {
      if(!cheat_AllLevels)
      {
          try{
             rmsWrite(data, rmsName);
          }
          catch(Exception ex)
          { 
            //ex.printStackTrace();
          }
          inClose();
      }
   }

/**************************************************************************************************/
/***                                                                                             **/
/***                        Functions for working with user's information                        **/
/***                                                                                             **/
/**************************************************************************************************/
      private void userRead()
      {
         String str;
         try{
            if(openDataInputStream(rmsRead(RMS_USER)))
            {
               str = readUTF();
               if(str != null) 
               {
                  strClear(user[USER_NAME]);
                  user[USER_NAME].append(str);
               }

               str = readUTF();
               if(str != null) 
               {
                  strClear(user[USER_ID]);
                  user[USER_ID].append(str);
               }
            }
         }
         catch(Exception ex)
         { 
            ex.printStackTrace(); 
         }
         inClose();
         str = null;
         System.gc();
      } 

      private void userWrite()
      {
         byte[] buff = null;
         try{
            openDataOutputStream(EDITOR_NAME_LENGTH + 32);

            if(user[USER_NAME] != null) writeUTF(user[USER_NAME].toString());
            if(user[USER_ID] != null) writeUTF(user[USER_ID].toString());

            buff = baos.toByteArray();
           
         }
         catch(Exception ex) 
         { 
            //ex.printStackTrace(); 
         }
         baosClose();
         outClose();

         rmsWrite(buff, RMS_USER);

         buff = null;
         System.gc();   
      }

/**************************************************************************************************/
/***                                                                                             **/
/***                        Functions for working with images                                    **/
/***                                                                                             **/
/**************************************************************************************************/

   public void imgRequest(int index)
   {
      if((index > -1) && (index < imgQueue.length)) imgQueue[index] = 0;
   }


   public void imgUnLoad(int index)
   {
      images[index] = null;
      imgQueue[index] = -1;
   }


   public void imgClear()
   {
      for(int i = 0; i < images.length; i++)
      {
         imgUnLoad(i);
      }
      System.gc();
   }


   private void loadFromBin(int binIndex)
   {
      int i, size, ptr, imageIndex, entryNum, foundPak;
      boolean found;
      byte[] b;
      
      try
      {
         if(binIndex <= COUNT_LEVELS_IN_JAR)
         {
            openInputStream(Integer.toString(binIndex) + ".bin");
         }
         else
         {
            openInputStream(rmsRead(RMS_LEVELS_BIN));
         }

         size = readInt();

         b = new byte[size];

         size = read(b, 0, b.length);

         inClose();

         for (i = 0, ptr = 0; ; ptr++)
         {
            size =   (b[i++] << 24) & 0xFF000000;
            size +=  (b[i++] << 16) & 0x00FF0000;
            size +=  (b[i++] <<  8) & 0x0000FF00;
            size +=  (b[i++]      ) & 0x000000FF;

            if (size == -1) break;

            found = false;
            for(imageIndex = 0; !found && imageIndex < imgQueue.length; imageIndex++)
            {  
               if(imgQueue[imageIndex] == 0 && binSpecs[imageIndex] > 0 )
               {
                  foundPak = (binSpecs[imageIndex] >> 8) & 0xFF;
                  entryNum = binSpecs[imageIndex] & 0xFF;

                  if(foundPak == binIndex && entryNum == ptr)
                  {
                     try
                     {
                        images[imageIndex] = Image.createImage(b, i, size);
                     }
                     catch(Exception ex)
                     {
                        ex.printStackTrace();
                     }
                     imgQueue[imageIndex] = -1;
                     found = true;
                  }
               }
            }
            i += size;
         }
         b = null;
         System.gc();
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }
   }


   public void loadImages()
   {
      boolean isSearching = true;
      int i;
      int pakNumber;

      // first loading paked images group by pak number 
      while(isSearching)
      {
         isSearching = false;
         for (i = 0; i < imgQueue.length; i++)
         {
            if(imgQueue[i] == 0 && binSpecs[i] > 0)
            {
               // found pak number - load all images from this pak
               pakNumber = (binSpecs[i] >> 8) & 0xFF;
               
               loadFromBin(pakNumber);
               imgQueue[i] = -1;
               isSearching = true;
            }
         }
      }
   }

/*******************************************************************************/
/***                                                                          **/
/***                Functions for working with strings                        **/
/***                                                                          **/
/*******************************************************************************/

   public void strRequest(int index)
   {
      strQueue[index] = 1;
   }


   public void strClear()
   {
      for(int i = 0; i < strings.length; i++)
      {
         strings[i] = null;
         strQueue[i] = -1;
      }
      System.gc();
   }


   private String getLevelString(int level)
   {
      int i;
      String str = "";
      if(groups[level] != null && jarLevelData[level] != null)
      {
         str = groups[level].name.toString();
         for(i = 0; i < jarLevelData[level].length; i++)
         {
            str += "|" + jarLevelData[level][i].name.toString();
         }
         str += "|" + strings[STR_BACK].toString();
      }
      return str;
   }

   public void strLoad()
   {
      int i, j, l;
      String str, tStr;
      try
      {
         openDataInputStream("sr.str");
         for(i = 0; i < strQueue.length; i++) 
         {
            str = "";
            switch(i){
               case STR_MENU_GROUPS:
                     if(strQueue[STR_MENU_GROUPS] == 1) 
                     {
                        str = strings[STR_GROUPS_TITLE].toString();
                        for(j = 0; j < groups.length; j++)
                        {
                           str += "|" + groups[j].name.toString();
                        }
                        str += "|" + strings[STR_BACK].toString();
                     }
                  break;
               case STR_MENU_JAR_LEVELS:
                     if(strQueue[STR_MENU_JAR_LEVELS] == 1)
                     {
                        for(l = 0; l < jarLevelData.length; l++)
                        {
                           tStr = getLevelString(l);
                           if(tStr.length() > str.length()) str = tStr;
                        }
                     }
                  break;
               case STR_MENU_RMS_LEVELS:
                     if((rmsLevelData != null) && (strQueue[STR_MENU_RMS_LEVELS] == 1))
                     {
                        str = groups[settings[SETTINGS_DL_INF]].name.toString();
                        for(j = 0; j < rmsLevelData.length; j++)
                        {
                           str += "|" + rmsLevelData[j].name.toString();
                        }
                        str += "|" + strings[STR_BACK];
                     }
                  break;
               default:
                     str = readUTF();
                  break;
            };

            if(strQueue[i] == 1) 
            {
               strings[i] = new StringBuffer(str);
               strWidth[i] = (short)strGetWidth(strings[i]);
               strQueue[i] = -1;
            }
            str = null;
         }
         inClose();
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }
      //#if !(SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF)
         // Delete menu item "sound" from menu "Options" for phones not supporting sound
         if(strings[STR_MENU_OPTIONS] != null)
         {
            i = strIndexOf(strings[STR_MENU_OPTIONS].toString(), '|', 2);
            j = strIndexOf(strings[STR_MENU_OPTIONS].toString(), '|', 3);
            strings[STR_MENU_OPTIONS].delete(i, j);
         }
         if(strings[STR_MENU_PAUSE] != null)
         {
            i = strings[STR_MENU_PAUSE].toString().lastIndexOf('|');
            j = strings[STR_MENU_PAUSE].toString().lastIndexOf('|', i - 1);
            strings[STR_MENU_PAUSE].delete(j, i);
         }
      //#endif
      //#if sp
      if(strings[STR_MENU_MAIN] != null)
      {
         i = strIndexOf(strings[STR_MENU_MAIN].toString(), '|', 3);
         j = strIndexOf(strings[STR_MENU_MAIN].toString(), '|', 4);
         strings[STR_MENU_MAIN].delete(i, j);
      }
      //#endif
   }

   private int strIndexOf(String str, int ch, int skipCount)
   {
      int i, j = 0;
      for(i = 0; i < skipCount; i++)
      {
         j = str.indexOf(ch, j + 1);
      }
      return j;
   }

/**************************************************************************************************/
/**                                                                                              **/
/**                                Function for working with text                                **/
/**                                                                                              **/
/**************************************************************************************************/
   
   private int textAddString(StringBuffer[] text, int j, String str)
   {
      if(text != null && j < text.length) text[j].append(str);
      if(textRowWidth != null && j < textRowWidth.length) textRowWidth[j] = (short)strGetWidth(new StringBuffer(str));
      return str.length();
   }

   private int textParser(StringBuffer[] text, StringBuffer str)
   {
      int i, j, len, maxLen, count, maxWidth;
      char ch, _ch;

      maxWidth = screenWidth - (TEXT_OFFSET << 1);
      j = 0;
      maxLen = 0;
      if(str != null)
      {
         strClear(tempStr);
         strClear(tempResStr);
         if(text != null) for(i = 0; i < text.length; i++) strClear(text[i]);
         count = str.length() - 1;
         for(i = 0; i <= count; i++)
         {
            ch = str.charAt(i);
            
            if(ch != '|') tempStr.append(ch);

            if((ch == '|') || (ch == ' ') || (ch == '.') || (i == (count)))
            {
               if((strGetWidth(tempResStr) + strGetWidth(tempStr)) > maxWidth)
               {
                  if(strGetWidth(tempStr) > maxWidth)
                  {
                     while(tempStr.length() > 0)
                     {
                        _ch = tempStr.charAt(0);
                        if((strGetWidth(tempResStr) + getFontWidth(_ch)) > maxWidth) 
                        {
                           if(strGetWidth(tempStr) > maxWidth)
                           {
                              len = textAddString(text, j++, tempResStr.toString());
                              maxLen = max(len, maxLen);

                              strClear(tempResStr);
                           }
                           else
                           {
                              break;
                           }
                        }
                        else
                        {
                           tempResStr.append(_ch);
                           tempStr.deleteCharAt(0);
                        }
                     }
                  }
                  
                  len = textAddString(text, j++, tempResStr.toString());
                  maxLen = max(len, maxLen);
               
               
                  if(i == (str.length() - 1)) 
                  {
                     len = textAddString(text, j++, tempStr.toString());
                     maxLen = max(len, maxLen);
                  }
                  else 
                  {
                     strClear(tempResStr);
                     tempResStr.append(tempStr.toString());
                  }
               }
               else if((ch == '|') || (i == (str.length() - 1)))
                    {
                       len = textAddString(text, j++, tempResStr.toString() + tempStr.toString());
                        maxLen = max(len, maxLen);

                       if(ch == '|') strClear(tempResStr);
                    }
                    else
                    {
                       tempResStr.append(tempStr.toString());
                    }
               strClear(tempStr);
            }
         }
      }
      return ((j << 16) & 0xFFFF0000) | (maxLen & 0x0000FFFF);
   }

/**************************************************************************************************/

   private void textInit(byte[] strIndex)
   {
      int i, res, count, length;
      
      count = length = 0;
      for(i = 0; i < strIndex.length; i++)
      {
         if(strings[strIndex[i]] != null)
         {
            res = textParser(null, strings[strIndex[i]]);
            if(((res >> 16) & 0x0000FFFF) > count) count = ((res >> 16) & 0x0000FFFF);
            if((res & 0x0000FFFF) > length) length = res & 0x0000FFFF;
         }
      }
      text = new StringBuffer[count];
      textRowWidth = new short[count];
      for(i = 0; i < text.length; i++) text[i] = new StringBuffer(length);
   }

/**************************************************************************************************/

   private void textInit(int strIndex, int posX, int posY, int width, int height, byte format)
   {
      textStrIndex = strIndex;
      if(text != null && strings != null && strIndex >= 0 && strIndex < strings.length)
      {
         int res = textParser(text, strings[strIndex]);
         
         textPosX = posX;
         textPosY = posY;

         textWidth = width;
         textHeight = height;

         textCountRow = (res >> 16) & 0x0000FFFF;
         textFirstRow = 0;

         textLastRow = (height - (TEXT_OFFSET << 1)) / (fontHeight + TEXT_LINE_SPACING);
         if(textLastRow > (textCountRow - 1)) textLastRow = textCountRow - 1;

         textFormat = format;
      }
   }

/**************************************************************************************************/
   
   private boolean textControl()
   {
      if(text != null && keyIsPressed)
      {
         if((keyCode == KEYS[KEY_UP]) || (keyCode == KEYS[KEY_NUM_2]))
         {
            if(textFirstRow > 0)
            {
               textFirstRow--;
               textLastRow--;
            }
         }
         else if((keyCode == KEYS[KEY_DOWN]) || (keyCode == KEYS[KEY_NUM_8]))
              {
                 if(textLastRow < (textCountRow - 1))
                 {
                    textFirstRow++;
                    textLastRow++;
                 }
              }
              else if((keyCode == KEYS[KEY_FIRE]) || (keyCode == KEYS[KEY_NUM_5]) || (keyCode == KEYS[KEY_SELECT]))
                   {
                      return true;
                   }
      }
      return false;
   }

/**************************************************************************************************/
   
   private void textDraw(byte bgFormat)
   {
      int i, y, x, width, height;
      if(text != null)
      {
         y = textPosY + ((textHeight - ((textLastRow - textFirstRow + 1) * (fontHeight + TEXT_LINE_SPACING) - TEXT_LINE_SPACING)) >> 1);

         if(y < textPosY) y = textPosY;
         
         switch(bgFormat){
            case TEXT_BORDER:
                  width = screenWidth - (textPosX << 1) + TEXT_OFFSET;
                  height = ((textLastRow - textFirstRow + 1) * (fontHeight + TEXT_LINE_SPACING)) + (TEXT_OFFSET << 1) - TEXT_LINE_SPACING - 1;
                  setClip(0, 0, screenWidth, screenHeight);
                  gd.setColor(UI_TextBGColor);
                  gd.fillRoundRect(textPosX - (TEXT_OFFSET >> 1), y - TEXT_OFFSET, width, height, 15, 15);
                  gd.setColor(0xFFFFFF);
                  gd.drawRoundRect(textPosX - (TEXT_OFFSET >> 1), y - TEXT_OFFSET, width, height, 15, 15);
                  
                  if(textFirstRow > 0) drawFrame(FRAMES[F_ARROW_UP], screenWidth >> 1, y - TEXT_OFFSET, 0, 0);
                  if(textLastRow < (textCountRow - 1)) drawFrame(FRAMES[F_ARROW_DOWN], screenWidth >> 1,  y - TEXT_OFFSET + height, 0, 0);
               break;
         }

         for(i = 0; i <= (textLastRow - textFirstRow) && (textFirstRow + i) < text.length; i++)
         {
            switch(textFormat){
               case TEXT_CENTER:
                     x = textPosX + (screenWidth - textRowWidth[textFirstRow + i]) >> 1;
                  break;
               default:
                     x = textPosX;
                  break;
            }
            drawString(text[textFirstRow + i], x, y + i * (fontHeight + TEXT_LINE_SPACING), 0, textWidth);
         }
      }
      else if(textStrIndex > 1 && textStrIndex < strings.length && strings[textStrIndex] != null)
           {
              drawString(strings[textStrIndex], (screenWidth - strWidth[textStrIndex]) >> 1, (screenHeight - fontHeight) >> 1);
           }
   }

    /*******************************************************************************/
    /***                                                                          **/
    /***                Functions for drawing strings                             **/
    /***                                                                          **/
    /*******************************************************************************/

   public static void strClear(StringBuffer strBuf)
   {
      if(strBuf != null && strBuf.length() > 0) strBuf.delete(0, strBuf.length());
   }

   public static int strGetWidth(StringBuffer strBuf)
   {
      int i, strWidth, strLen;
      
      strLen = strBuf.length();
      strWidth = 0;
      for(i = 0; i < strLen; i++)
      {
         strWidth += Constants.WChar[strGetCharIndex(strBuf.charAt(i))];
      }
      return strWidth;
   }

   public static int getFontWidth(char ch)
   {
      int i = strGetCharIndex(ch);
      if(i >= 0 && i < WChar.length)
      {
         return WChar[i];
      }
      else
      {
         return 0;
      }
   }

   public static int strGetCharIndex(char ch)
   {
      if((ch >= 'a') && (ch <= 'z'))
      {
         return (int)(ch - 'a') + 1;
      }
      if((ch >= 'A') && (ch <= 'Z'))
      {
         return (int)(ch - 'A') + 1;
      }
      if((ch >= '0') && (ch <= '9'))
      {
         return (int)(ch - '0') + 27;
      }
      switch(ch) {
         case '~':  return 37;
         case '!':  return 38;
         case '"':
         case '\'': return 39;
         case '?':  return 40;
         case '-':  return 41;
         case '.':  return 42;
         case ',':  return 43;
         case ':':  return 44;
         case '+':  return 45;
         case '@':  return 46;
         case '$':  return 47;
         case '^':  return 48;

         //#if french || german || italian || spanish
            case 0xA1: return 49; // !
            case 0xBF: return 50; // ?

            case 0xE0:            // a
            case 0xC0: return 51; // A
            case 0xE1:            // a
            case 0xC1: return 52; // A
            case 0xE2:            // a
            case 0xC2: return 53; // A 
            case 0xE4:            // a
            case 0xC4: return 54; // A

            case 0xE8:            // e
            case 0xC8: return 55; // E
            case 0xE9:            // e
            case 0xC9: return 56; // E
            case 0xEA:            // e
            case 0xCA: return 57; // E
            case 0xEB:            // e
            case 0xCB: return 58; // E

            case 0xEC:            // i
            case 0xCC: return 59; // I
            case 0xED:            // i
            case 0xCD: return 60; // I
            case 0xEE:            // i
            case 0xCE: return 61; // I
            case 0xEF:            // i
            case 0xCF: return 62; // I

            case 0xF1:            // n
            case 0xD1: return 63; // N

            case 0xF2:            // o
            case 0xD2: return 64; // O
            case 0xF3:            // o
            case 0xD3: return 65; // O
            case 0xF4:            // o
            case 0xD4: return 66; // O
            case 0xF6:            // o
            case 0xD6: return 67; // O

            case 0xF9:            // u
            case 0xD9: return 68; // U 
            case 0xFA:            // u
            case 0xDA: return 69; // U
            case 0xFB:            // u
            case 0xDB: return 70; // U
            case 0xFC:            // u
            case 0xDC: return 71; // U

            case 0xDF: return 72; // B

            case 0xE7:            // c
            case 0xC7: return 73; // C

            case 0x9C:            // ce
            case 0x8C: return 74; // CE

            case 0xE6:            // ae
            case 0xC6: return 75; // AE
         //#elif unicode
            case '\u00E0': return 49;
            case '\u00E1': return 50;
            case '\u00E3': return 51;
            case '\u00E4': return 52;
            case '\u00E5': return 53; //a

            case '\u00E6': return 54;

            case '\u00E7': return 55;

            case '\u00E8': return 56;
            case '\u00E9': return 57;
            case '\u00EA': return 58;
            case '\u00EB': return 59; //e

            case '\u00EC': return 60;
            case '\u00ED': return 61;
            case '\u00EE': return 62;
            case '\u00EF': return 63; //i

            case '\u00F1': return 64; //n

            case '\u00F2': return 65;
            case '\u00F3': return 66;
            case '\u00F4': return 67;
            case '\u00F5': return 68; //o

            case '\u00F9': return 69;
            case '\u00FA': return 70;
            case '\u00FB': return 71;
            case '\u00FC': return 72; //u
         //#endif
      }
      return 0;
   }

   public void drawString(StringBuffer str, int x, int y, int width)
   {
      drawString(str, x, y, 0, width);
   }

   public static void drawString(StringBuffer str, int x, int y, int offsetX, int width)
   {
      if(str != null)
      {
         int chPos = str.toString().lastIndexOf('^');
         if(chPos != -1)
         {
            strClear(tempResStr);
            tempResStr.append(str.toString());
            tempResStr.delete(chPos, tempResStr.length());
            drawString(tempResStr, x + 1, y);

            strClear(tempResStr);
            tempResStr.append(str.toString());
            tempResStr.delete(0, chPos + 1);
            drawString(tempResStr, (x + width) - strGetWidth(tempResStr) - 1, y);
         }
         else drawString(str, x + offsetX, y);
      }
   }

   public void drawString(int value, int x, int y, byte textFormat)
   {
      drawString(Integer.toString(value), x, y, textFormat);
   }
   
   public void drawString(String str, int x, int y, byte textFormat)
   {
      switch(textFormat){
         case LEFT_TO_RIGHT:
               drawString(new StringBuffer(str), x, y);
            break;
         case RIGHT_TO_LEFT:
               _drawString(new StringBuffer(str), x, y);
            break;
      }
   }
   
   public static void drawString(StringBuffer strBuf, int x, int y)
   {            
      int i, j, strWidth;
      char ch;

      if(strBuf != null)
      {
         strWidth = 0;
         for(i = 0; i < strBuf.length(); i++) 
         {
            ch = strBuf.charAt(i);
            j = strGetCharIndex(ch);
            drawChar(j, x + strWidth, y);
            strWidth += WChar[j];
         }
      }
   }

   public void _drawString(StringBuffer strBuf, int x, int y)
   {            
      int i, j, strWidth;
      char ch;

      if(strBuf != null)
      {
         strWidth = 0;
         for(i = strBuf.length() - 1; i >= 0; i--) 
         {
            ch = strBuf.charAt(i);
            j = strGetCharIndex(ch);
            strWidth += WChar[j];
            drawChar(j, x - strWidth, y);
         }
      }
   }
   

   public static void drawChar(int chNum, int x, int y)
   {
      if(chNum > 0 && chNum < WChar.length)
      {
         if(setClip(x, y, WChar[chNum], fontHeight)) gd.drawImage(images[IMG_ALPHABET], x - charOffset[chNum - 1], y - (RowInImg[chNum] * fontHeight), 0);
      }
   }

/**************************************************************************************************/

   public void drawFrame(long frame, int x, int y, int cX, int cY)
   {
      int imgIndex = (int)(frame & 0xFF);
      int offsetX  = (int)((frame >> 8) & 0xFF);
      int offsetY  = (int)((frame >> 16) & 0xFF);
      int width    = (int)((frame >> 24) & 0xFF);
      int height   = (int)((frame >> 32) & 0xFF);
      int anchorX  = (int)((frame >> 40) & 0xFF);
      int anchorY  = (int)((frame >> 48) & 0xFF);

      if(images[imgIndex] != null)
      {
         if(setClip(x - anchorX, y - anchorY, width - cX, height - cY))
         {
            gd.drawImage(images[imgIndex], x - offsetX - anchorX, y - offsetY - anchorY, 0);
         }                                      
      }
   }

   private void drawFrameset(int index, int x, int y)
   {
      int i, frame, fx, fy;
      
      for(i = 0; i < FRAMESETS[index].length; i++)
      {
         frame = FRAMESETS[index][i] & 0xFF;

         fx = x + ((FRAMESETS[index][i] << 16) >> 24);
         fy = y + ((FRAMESETS[index][i] << 8) >> 24);

         drawFrame(FRAMES[frame], fx, fy, 0, 0);
      }
   }

/**************************************************************************************************/

   private void drawTime(long time, int x, int y, byte textFormat)
   {
      timeToBuf(time);
      switch(textFormat){
         case LEFT_TO_RIGHT:
               drawString(timeStr, x, y);
            break;
         case RIGHT_TO_LEFT:
               _drawString(timeStr, x, y);
            break;
      }
   }
   
/**************************************************************************************************/

   public void timeToBuf(long time)
   {
      int t_t, t_ms, t_s, t_secs, t_mins;

      t_t = fpToInt(fpMul(fpToFP(time), FP_10));

      t_ms = t_t % 100;

      t_s = fpToInt(fpMul(fpToFP(time), FP_1000));

      t_secs = t_s % 60;

      t_mins = fpToInt(fpMul(fpToFP(t_s), FP_60));

      strClear(timeStr);
      if(t_mins < 10) timeStr.append('0');
      timeStr.append(t_mins);
      timeStr.append(':');
      if(t_secs < 10) timeStr.append('0');
      timeStr.append(t_secs);
      timeStr.append(':');
      if(t_ms < 10) timeStr.append('0');
      timeStr.append(t_ms);
   }


/**************************************************************************************************/
/**                                                                                              **/
/**                Functions for working with editor (name or phone number                      **/
/**                                                                                              **/
/**************************************************************************************************/

   private void editorInit(char[][] chars)
   {
      int i, j;
      if(chars != null)
      {

         editorCountChars = EDITOR_NAME_LENGTH;
         if(user != null && user[USER_NAME].length() > 0) 
         {
            editorCurrentChar = user[USER_NAME].length();
            editorCurRow = chars.length - 1;
            editorCurCol = chars[0].length - 1;
         }
         else
         {
            editorCurrentChar = 0;
            editorCurRow = 0;
            editorCurCol = 0;
         }

         editorChars = new char[chars.length][chars[0].length];
         for(i = 0; i < chars.length; i++)
            for(j = 0; j < chars[i].length; j++)
               editorChars[i][j] = chars[i][j];
         editorStr = new char[editorCountChars];
         if(user != null && user[USER_NAME].length() > 0) 
         {
            for(i = 0; (i < editorStr.length) && (i < user[USER_NAME].length()); i++) editorStr[i] = user[USER_NAME].charAt(i);
         }
   
         //#if !FULL_CANVAS
            if(!getLabelCmd(cmdLeft).equals(strings[STR_SELECT])) 
            {
               removeAllCmds();
               addCmd(KEY_SELECT, strings[STR_SELECT]);
            }
         //#endif

         posX = (screenWidth - (EDITOR_CELL_WIDTH * chars[0].length)) >> 1;
         posY = (screenHeight - (EDITOR_CELL_HEIGHT * chars.length)) >> 1;
      }
   }

/**************************************************************************************************/
/**************************************************************************************************/

   private void drawRaster()
   {
      if(images[IMG_RASTER] != null)
      {     
         setClip(0, 0, screenWidth, screenHeight);
         for(int i = 0; i < screenHeight; i += 16)
            for(int j = 0; j < screenWidth; j += 16)
            {
               gd.drawImage(images[IMG_RASTER], j, i, 20);
            }
      }
   }

//******************************************************************************

   public static void fillBG(int color, int x, int y, int w, int h)
   {
      if(setClip(x, y, w, h))
      {
         gd.setColor(color);
         gd.fillRect(x, y, w, h);
      }
   }


   public static boolean setClip(int x, int y, int w, int h)
   {

      // range check values to fit the screen
      if((x >= screenWidth) || (y >= screenHeight) || (w == 0) || (h == 0)) return false;

      //if(w == 0) w = screenWidth;
      //if(h == 0) h = screenHeight;

      if(x < 0)
      {
         w += x;
         if(w <= 0) return false;
         x = 0;
      }
      if(y < 0)
      {
         h += y;
         if(h <= 0) return false;
         y = 0;
      }

      if((x + w) > screenWidth) w = screenWidth - x;
      if((y + h) > screenHeight) h = screenHeight - y;

      gd.setClip(x, y, w, h);
      return true;
   }

/******************************************************************************/

   private void creatUniCode(StringBuffer str, int count)
   {
      int i, j;
      rndOpen();

      strClear(str);
      for(i = 0; (i < count) && (i < str.capacity()); i++)
      {
         j = (rndNextInt() & 0x07FFFFFFF) % 36;
         if(j < 10) 
         {
            str.append((char)('0' + j));
         }
         else
         {
            str.append((char)('A' + j - 10));
         }
      }
      rndClose();
   }

/******************************************************************************/

   private void gameStartPause()
   {
      timeStartPause = System.currentTimeMillis();
   }

   private void gameFinishPause()
   {
      long duration = System.currentTimeMillis() - timeStartPause;
      timeStartGame += duration;
      timeStartLoop += duration;
   }

/**************************************************************************************************/

   private void initGameSession()
   {
      //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
         soundStop(SOUND_BGMUSIC);
      //#endif

      groupCurrent = 0;
      shipCurrent = 0;

      levelTotalTime = 0;
      levelTotalScores = 0;
      levelTotalResultScores = 0;
      for(int i = 0; i < passedLevels.length; i++) passedLevels[i] = 0;

      creatUniCode(gameSession, GAME_SESSION_LENGTH);

   }

/**************************************************************************************************/

   private void setScreen(int strIndex, boolean restoreState, long progress)
   {
      int res, oldGameState = gameState;
      
      //#if !FULL_CANVAS
         removeAllCmds();
      //#endif
      textInit(strIndex, 0, 0, screenWidth, screenHeight, TEXT_CENTER);

      this.progress = progress;

      gameState = GS_SET_SCREEN;
      doRepaint();
      
      if(restoreState) gameState = oldGameState;
   }

/**************************************************************************************************/

   private void setPlace(int place)
   {
      if(strings[STR_PLACE] !=null)
      {
         strClear(tempStr);
         if(place < 10) tempStr.append(place + " ");
         else tempStr.append(place);
         strings[STR_PLACE].delete(strings[STR_PLACE].length() - 2, strings[STR_PLACE].length());
         strings[STR_PLACE].append(tempStr);
      }
   }

/**************************************************************************************************/
/**                                                                                              **/
/** UPDATE OBJECTS FUNCTIONS                                                                     **/
/**                                                                                              **/
/**************************************************************************************************/
   
   private void updateGameObjects()
   {
      int tInt, i;
      switch(gameState){
// UPDATE GAME  **********************************************************************************/
         case GS_GAME:
               
               switch(gameSubState){
                  case GSS_GAME_PLAY:
                        if(keyIsPressed)
                        {
                           //#if !FULL_CANVAS
                           if(keyCode == KEYS[KEY_CANCEL])
                           //#else
                           if(keyCode == KEYS[KEY_SELECT])
                           //#endif
                           {
                              gameStartPause();
                              hideNote();
                              gameSubState = GSS_GAME_PAUSE;
                              menu.initMenu(GSS_MENU_PAUSE, 1);
                              keyIsPressed = false;
                           }
                           else if((keyCode == control[CONTROL_POWER_UP]) || (keyCode == KEYS[KEY_UP]))
                                {
                                   isGasKeyPressing = true;
                                }
                                else if((keyCode == control[CONTROL_TURN_LEFT]) || (keyCode == KEYS[KEY_LEFT]))
                                     {
                                        if(isGasKeyPressing) isGasKeyPressing = false;
                                        ship.startLeftEngine();
                                     }
                                     else if((keyCode == control[CONTROL_TURN_RIGHT]) || (keyCode == KEYS[KEY_RIGHT]))
                                          {
                                             if(isGasKeyPressing) isGasKeyPressing = false;
                                             ship.startRightEngine();
                                          }
                                          else if((keyCode == control[CONTROL_BRAKE]) || (keyCode == KEYS[KEY_DOWN]))
                                               {
                                                  if(isGasKeyPressing) isGasKeyPressing = false;
                                                  ship.startBrakeEngine();
                                               }
                                               else if((keyCode == control[CONTROL_USE_ITEM]) || (keyCode == KEYS[KEY_FIRE]))
                                                    {
                                                       if(isGasKeyPressing) isGasKeyPressing = false;
                                                       switch(ship.itemType){
                                                         case ITEM_POWERUP:
                                                               ship.activatePowerUp();
                                                            break;
                                                         case ITEM_WEAPON:
                                                               if(ship.shooter.isReady()) addShot(ship, ship.weaponType);
                                                            break;
                                                       }
                                                    }
                                                    else if(keyCode == control[CONTROL_UP_LEFT])
                                                         {
                                                            isGasKeyPressing = true;
                                                            ship.startLeftEngine();
                                                         }
                                                         else if(keyCode == control[CONTROL_UP_RIGHT])
                                                              {
                                                                 isGasKeyPressing = true;
                                                                 ship.startRightEngine();
                                                              }
                           keyIsPressed = false;
                        }
                        if(keyIsReleased)
                        {
                           if((keyCode == control[CONTROL_POWER_UP]) || (keyCode == KEYS[KEY_UP]))
                           {
                              isGasKeyPressing = false;
                           }
                           else if((keyCode == control[CONTROL_TURN_LEFT]) || (keyCode == KEYS[KEY_LEFT]) || (keyCode == control[CONTROL_TURN_RIGHT]) || (keyCode == KEYS[KEY_RIGHT]))
                                {
                                   ship.stopTurnEngine(SHIP_TURNSTATE_FREE);
                                }
                                else if((keyCode == control[CONTROL_BRAKE]) || (keyCode == KEYS[KEY_DOWN]))
                                     {
                                       ship.stopBrakeEngine();
                                     }
                                     else if((keyCode == control[CONTROL_UP_LEFT]) || (keyCode == control[CONTROL_UP_RIGHT]))
                                          {
                                             isGasKeyReleasing = false;
                                             ship.stopTurnEngine(SHIP_TURNSTATE_FREE);
                                          }
                           keyIsReleased = false;
                        }
                     break;

               }

            break;

      }
   }

   public void updateObjects() 
   {
      int i, tInt;
      switch(gameState){
// UPDATE GS_MENU **********************************************************************************/
         case GS_MENU:
               
               switch(gameSubState){
                  case GSS_MENU_SELECT_KEY:

                        if(keyIsPressed)
                        {
                           if(isKeyFree(keyCode, controlSelectedItem - 1))
                           {
                              control[controlSelectedItem - 1] = (byte)keyCode;

                              strings[STR_KEY_SELECTED].delete(strings[STR_KEY_SELECTED].toString().indexOf(':') + 1, strings[STR_KEY_SELECTED].length());
                              i = getKeyName(control[controlSelectedItem - 1]);
                              if(i > -1)
                              {
                                 strings[STR_KEY_SELECTED].append(strings[i].toString());
                              }
                              
                              setScreen(STR_KEY_SELECTED, true, -1);
                              wait(2000);

                              gameState = GS_MENU;
                              gameSubState = menu.initMenu(GSS_MENU_CONTROL, controlSelectedItem);
                           }
                           else
                           {
                              setScreen(STR_KEY_USED, true, -1);
                              wait(1000);
                           }
                        }
                     break;

                  default:
                        if((gameSubState == GSS_MENU_MAIN) && ((int)(cheatCode & 0xffffffff) == CHEAT_ALL_LEVELS) && (!cheat_AllLevels))
                        {
                           cheat_AllLevels = true;
                           settings[SETTINGS_GROUP] = (byte)(groups.length - 1);
                           settings[SETTINGS_LEVEL] = settings[SETTINGS_COUNT_LEVELS];
                           setScreen(STR_CHEAT, true, -1);
                           wait(1000);
                        }

                        tInt = menu.checkState(keyCode, keyIsPressed);
                        
                        if(tInt > 0)
                        {
                           switch(gameSubState){
                              /********************************************************************/
                              case GSS_MENU_MAIN:
                                    //#if sp
                                      int mpOffset = -1;
                                    //#else 
                                      int mpOffset = 0;
                                    //#endif
                                    if(tInt == 1) // New game
                                    {
                                       initGameSession();
                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_GROUPS, 1);
                                    }
                                    else  if(tInt == 2) // Hiscores
                                          {
                                             gameState = GS_INTERNET;
                                             gameSubState = GSS_INTERNET_DL_TOTAL_SCORES;
                                          }
                                          //#if mp
                                          else  if(tInt == 3) // Download update
                                                {
                                                   gameState = GS_INTERNET;
                                                   gameSubState = GSS_INTERNET_DL_UPDATE;
                                                }
                                          //#endif
                                                else  if(tInt == 4 + mpOffset) // Options
                                                      {
                                                         gameState = GS_MENU;
                                                         gameSubState = menu.initMenu(GSS_MENU_OPTIONS, 1);
                                                      }
                                                      else  if(tInt == 5 + mpOffset) // About
                                                            {
                                                               textInit(STR_ABOUT, TEXT_OFFSET, TEXT_OFFSET, screenWidth - (TEXT_OFFSET << 1), screenHeight - (TEXT_OFFSET << 1), TEXT_CENTER);
                                                               gameState = GS_ABOUT;
                                                            }
                                                            else  if(tInt == 6 + mpOffset) // Quit
                                                                  {
                                                                     gameState = GS_MENU;
                                                                     gameSubState = menu.initMenu(GSS_MENU_EXIT, 1);
                                                                  }
                                 break;

                              /********************************************************************/
                              case GSS_MENU_OPTIONS:
                                    //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                                       int soundOffset = -1;
                                    //#else
                                       int soundOffset = 0;
                                    //#endif
                                    if(tInt == 1) // Control
                                    {
                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_CONTROL, 1);
                                    }
                                    //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                                    else  if(tInt == 2) // Sound
                                          {
                                             gameState = GS_MENU;
                                             gameSubState = menu.initMenu(GSS_MENU_SOUND, 2 - settings[SETTINGS_SOUND]);
                                          }
                                    //#endif
                                    else  if(soundOffset + tInt == 2)
                                          {
                                             editorInit(EDITOR_NAME_CHARS);
                                             gameState = GS_EDITOR;
                                             gameSubState = ESS_EDIT_NAME;
                                          }
                                    else  if(soundOffset + tInt == 2) // Back
                                          {
                                             gameState = GS_MENU;
                                             gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                                          }
                                 break;

                              /********************************************************************/
                              //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                              case GSS_MENU_SOUND:
                                       if(tInt > 0 && tInt < 3)
                                       {
                                          settings[SETTINGS_SOUND] = (byte)(2 - tInt);
                                          if(settings[SETTINGS_SOUND] == 0) soundStop(SOUND_BGMUSIC);
                                          writeSettings(settings, RMS_SETTINGS);
                                       }
                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_OPTIONS, 1);
                                 break;
                              //#endif
                              
                              /********************************************************************/
                              //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                              case GSS_MENU_SOUND_STARTUP:
                                       if(tInt == 1)
                                       {
                                          soundPlay(SOUND_BGMUSIC);
                                       }
                                       settings[SETTINGS_SOUND] = (byte)(2 - tInt);
                                       writeSettings(settings, RMS_SETTINGS);
                                       //#if !FULL_CANVAS
                                          removeAllCmds();
                                       //#endif
                                       timer.set(3500);
                                       gameState = GS_SPLASH;
                                 break;
                              //#endif
                              /********************************************************************/
                              case GSS_MENU_CONTROL:
                                    if(tInt == menu.itemsCount - 1)
                                    {
                                       writeSettings(control, RMS_CONTROL);

                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_OPTIONS, 1);
                                    }
                                    else
                                    {
                                       controlSelectedItem = tInt;
                                       strings[STR_MENU_SELECT_KEY].delete(strings[STR_MENU_SELECT_KEY].toString().indexOf('|') + 1, strings[STR_MENU_SELECT_KEY].length());

                                       i = getKeyName(control[controlSelectedItem - 1]);
                                       if(i > -1)
                                       {
                                          strings[STR_MENU_SELECT_KEY].append(strings[i].toString());
                                       }

                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_SELECT_KEY, 1);
                                    }
                                 break;

                              /********************************************************************/
                              case GSS_MENU_EXIT:
                                    switch(tInt){
                                       case 1: // Yes
                                             gameState = GS_EXIT;
                                          break;
                                       case 2: // No
                                             gameState = GS_MENU;
                                             gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                                          break;
                                    }
                                 break;

                              /********************************************************************/
                              case GSS_MENU_GROUPS:
                                    if(tInt == menu.itemsCount - 1)
                                    {
                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                                    }
                                    else 
                                    {
                                       groupCurrent = tInt - 1;
                                       levelCurrent = 0;
                                       
                                       gameState = GS_MENU;
                                       if(groupCurrent < COUNT_LEVELS_IN_JAR)
                                       {
                                          
                                          strClear(strings[STR_MENU_JAR_LEVELS]);
                                          strings[STR_MENU_JAR_LEVELS].append(getLevelString(groupCurrent));
                                          gameSubState = menu.initMenu(GSS_MENU_JAR_LEVELS, 1);
                                       }
                                       else
                                       {
                                          if((settings[SETTINGS_DL_INF] == groupCurrent) && (settings[SETTINGS_DL_SPECS] == groupCurrent) && (settings[SETTINGS_DL_BIN] == groupCurrent))
                                          {
                                             gameSubState = menu.initMenu(GSS_MENU_RMS_LEVELS, 1);
                                          }
                                          else
                                          {
                                             gameSubState = menu.initMenu(GSS_MENU_DL_GROUP, 1);
                                          }
                                       }
                                    }
                                 break;

                              /********************************************************************/
                              case GSS_MENU_JAR_LEVELS:
                              case GSS_MENU_RMS_LEVELS:
                                    if(tInt == menu.itemsCount - 1)
                                    {
                                       gameState = GS_MENU;
                                       gameSubState = menu.initMenu(GSS_MENU_GROUPS, groupCurrent + 1);
                                    }
                                    else
                                    {
                                       levelCurrent = tInt - 1;
                                       initSelectShipScreen();
                                    }
                                 break;

                              /********************************************************************/
                              case GSS_MENU_DL_GROUP:
                                    switch(tInt){
                                       case 1: // DL levels from server
                                             gameState = GS_INTERNET;
                                             gameSubState = GSS_INTERNET_DLLEVELS;
                                          break;
                                       case 2: // back
                                             gameState = GS_MENU;
                                             gameSubState = menu.initMenu(GSS_MENU_GROUPS, groupCurrent + 1);
                                          break;
                                    }
                                 break;

                              /********************************************************************/
                              case GSS_MENU_UL_TOTAL_SCORES:
                              case GSS_MENU_TOTAL_RETRY:
                                    switch(tInt){
                                       case 1: // UL results to server
                                             gameState = GS_INTERNET;
                                             gameSubState = GSS_INTERNET_UL_TOTAL_SCORES;
                                          break;
                                       case 2: // next track
                                             if(levelResult == LR_FAILED)
                                             {
                                                setScreen(STR_GAME_OVER, true, -1);
                                                wait(3000);
                                             }
                                             gameState = GS_MENU;
                                             gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                                          break;
                                    }
                                 break;
                           }
                        }
                     break;
               }

               keyIsPressed = false;
               keyIsReleased = false;
            break;

// UPDATE GS_MENU **********************************************************************************/
         case GS_SELECTSHIP:

               if(flag)
               {
                  if(textControl()) flag = false;
               }
               else
               {
                  if((keyCode == KEYS[KEY_LEFT]) || (keyCode == KEYS[KEY_NUM_4]))
                  {
                     if(shipCurrent > 0) 
                     {
                        shipCurrent--;

                        shipBodyState = (byte)(SHIP_ANIMATIONS[PLAYER_SHIPS[shipCurrent]].length - 1);

                        tInt = ssOldShipPosX;

                        ssOldShip = ssCurrentShip;
                        ssOldShipPosX = ssCurrentShipPosX;
                        ssOldShipWidth = ssCurrentShipWidth;
                        ssOldShipAnim.startAnimation(SHIP_ANIMATIONS[PLAYER_SHIPS[ssOldShip]][shipBodyState], ANIMATION_PLAY_REPEAT);

                        ssCurrentShip = shipCurrent;
                        ssCurrentShipWidth = getShipWidth(ssCurrentShip, 1);
                        if(ssStep != 0) ssCurrentShipPosX = tInt;
                        else ssCurrentShipPosX = ssShipAreaX1 - (ssCurrentShipWidth >> 1);
                        ssCurrentShipAnim.startAnimation(SHIP_ANIMATIONS[PLAYER_SHIPS[ssCurrentShip]][shipBodyState], ANIMATION_PLAY_REPEAT);

                        ssStep = 3;
                         
                        textInit(PLAYER_SHIPS_DESCRIPTION[shipCurrent], TEXT_OFFSET, TEXT_OFFSET, screenWidth - (TEXT_OFFSET << 1), screenHeight - (TEXT_OFFSET << 1), TEXT_LEFT);
                     }
                  }
                  else if((keyCode == KEYS[KEY_RIGHT]) || (keyCode == KEYS[KEY_NUM_6]))
                       {
                          if(shipCurrent < (PLAYER_SHIPS.length - 1)) 
                          {
                             shipCurrent++;
                             
                             shipBodyState = 0;
                             
                             tInt = ssOldShipPosX;

                             ssOldShip = ssCurrentShip;
                             ssOldShipPosX = ssCurrentShipPosX;
                             ssOldShipWidth = ssCurrentShipWidth;
                             ssOldShipAnim.startAnimation(SHIP_ANIMATIONS[PLAYER_SHIPS[ssOldShip]][shipBodyState], ANIMATION_PLAY_REPEAT);

                             ssCurrentShip = shipCurrent;
                             ssCurrentShipWidth = getShipWidth(ssCurrentShip, 1);
                             if(ssStep != 0) ssCurrentShipPosX = tInt;
                             else ssCurrentShipPosX = ssShipAreaX2 + (ssCurrentShipWidth >> 1);
                             ssCurrentShipAnim.startAnimation(SHIP_ANIMATIONS[PLAYER_SHIPS[ssCurrentShip]][shipBodyState], ANIMATION_PLAY_REPEAT);
                             
                             ssStep = -3;
                              
                             textInit(PLAYER_SHIPS_DESCRIPTION[shipCurrent], TEXT_OFFSET, TEXT_OFFSET, screenWidth - (TEXT_OFFSET << 1), screenHeight - (TEXT_OFFSET << 1), TEXT_LEFT);
                          }
                       }

                  tInt = menu.checkState(keyCode, keyIsPressed);
                  switch(tInt){
                     case 1: // Select ship (start game)
                           if(groupCurrent < COUNT_LEVELS_IN_JAR)
                           {
                              if(jarLevelData != null) loadLevel(jarLevelData[groupCurrent][levelCurrent]);
                           }
                           else
                           {
                              if(rmsLevelData != null) loadLevel(rmsLevelData[levelCurrent]);
                           }
                        break;
                     case 2: // Info
                           flag = true;
                        break;
                     case 3: // Back
                           gameState = GS_MENU;
                           if(groupCurrent < COUNT_LEVELS_IN_JAR)
                           {
                              strClear(strings[STR_MENU_JAR_LEVELS]);
                              strings[STR_MENU_JAR_LEVELS].append(getLevelString(groupCurrent));
                              gameSubState = menu.initMenu(GSS_MENU_JAR_LEVELS, levelCurrent + 1);
                           }
                           else
                           {
                              gameSubState = menu.initMenu(GSS_MENU_RMS_LEVELS, levelCurrent + 1);
                           }
                        break;
                  }
               }
               keyIsPressed = false;
               keyIsReleased = false;
            break;

/** UPDATE GSS_GAME_PAUSE ******************************************************************************/
         case GS_GAME:
               tInt = menu.checkState(keyCode, keyIsPressed);
               switch(gameSubState){
                  case GSS_GAME_PAUSE:
                        switch(tInt){
                           case 1: // Resume game
                                 gameFinishPause();
                                 //#if !FULL_CANVAS
                                    if(!getLabelCmd(cmdRight).equals(strings[STR_PAUSE])) 
                                    {
                                       removeAllCmds();
                                       addCmd(KEY_CANCEL, strings[STR_PAUSE]);
                                    }
                                 //#endif
                                 gameSubState = GSS_GAME_PLAY;
                              break;
                           case 2: // Restart game
                                 initLevel();
                              break;
                           //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                           case 3:
                                 gameSubState = GSS_GAME_OPTIONS;
                                 menu.initMenu(GSS_MENU_INGAME_OPTIONS, 1);
                              break;
                           case 4:
                           //#else
                           case 3:
                           //#endif
                                 setScreen(STR_LOADING, true, -1);

                                 destroyLevel();

                                 initIntro();

                                 gameState = GS_MENU;
                                 if(groupCurrent < COUNT_LEVELS_IN_JAR)
                                 {
                                    strClear(strings[STR_MENU_JAR_LEVELS]);
                                    strings[STR_MENU_JAR_LEVELS].append(getLevelString(groupCurrent));
                                    gameSubState = menu.initMenu(GSS_MENU_JAR_LEVELS, levelCurrent + 1);
                                 }
                                 else
                                 {
                                    gameSubState = menu.initMenu(GSS_MENU_RMS_LEVELS, levelCurrent + 1);
                                 }
                              break;
                        }
                        keyIsPressed = false;
                        keyIsReleased = false;
                     break;

                  //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                  case GSS_GAME_OPTIONS:
                        switch(tInt){
                           case 1: // Sound options
                                 gameSubState = GSS_GAME_SOUND;
                                 menu.initMenu(GSS_MENU_SOUND, 2 - settings[SETTINGS_SOUND]);
                              break;
                           case 2: // Back
                                 gameSubState = GSS_GAME_PAUSE;
                                 menu.initMenu(GSS_MENU_PAUSE, 1);
                              break;
                        }
                        keyIsPressed = false;
                        keyIsReleased = false;
                     break;

                  case GSS_GAME_SOUND:
                        if(tInt > -1)
                        {
                           if(tInt > 0 && tInt < 3)
                           {
                              settings[SETTINGS_SOUND] = (byte)(2 - tInt);
                              if(settings[SETTINGS_SOUND] == 0) soundStop(soundId);
                           }
                           gameSubState = GSS_GAME_OPTIONS;
                           menu.initMenu(GSS_MENU_INGAME_OPTIONS, 1);
                        }
                        keyIsPressed = false;
                        keyIsReleased = false;
                     break;
                  //#endif
                  
                  case GSS_GAME_FINISHED:
                        switch(tInt){
                           case 1: // End game
                                 setScreen(STR_LOADING, true, -1);

                                 destroyLevel();

                                 levelTotalTime += levelTime;
                                 levelTotalScores += levelScores;
                                 levelTotalResultScores += levelResultScores;

                                 initIntro();

                                 keyIsPressed = false;
                                 keyIsReleased = false;
                                 
                                 timer.set(5000);
                                 gameState = GS_SHOW_LEVEL_SCORES;
                              break;
                           case 2: // Replay level
                                 initLevel();
                              break;
                        }
                        keyIsPressed = false;
                        keyIsReleased = false;
                     break;

                  default:
                        tInt = (int)(cheatCode & 0xffffffff);
                        flag = false;
                        if(cheatCode == CHEAT_KILL_NPC)
                        {
                           for(i = 0; i < npcShips.length; i++)
                           {
                              if(npcShips[i].shipState == SHIP_STATE_MOVE) npcShips[i].destroyShip();
                           }
                           flag = true;
                        }
                        else if(ship.itemType == ITEM_POWERUP)
                             {
                                if(tInt == CHEAT_SHIELD && ship.powerupType == SPECIALITEM_SHIELD)
                                {
                                   cheat_Shield = true;
                                   flag = true;
                                }
                                else if(tInt == CHEAT_NITRO && ship.powerupType == SPECIALITEM_NITRO)
                                     {
                                        cheat_Nitro = true;
                                        flag = true;
                                     }
                             }
                             else if(ship.itemType == ITEM_WEAPON)
                                  {
                                     if(tInt == CHEAT_MISSILES && ship.weaponType == WEAPON_ROCKET)
                                     {
                                        cheat_Missiles = true;
                                        flag = true;
                                     }
                                     else if(tInt == CHEAT_BOMBS && ship.weaponType == WEAPON_BOMB)
                                          {
                                             cheat_Bomb = true;
                                             flag = true;
                                          }
                                          else if(tInt == CHEAT_MINES && ship.weaponType == WEAPON_MINE)
                                               {
                                                  cheat_Mine = true;
                                                  flag = true;
                                               }
                                  }
                        if(flag)
                        {
                           cheatCode = 0;
                           showNote(STR_CHEAT, 1000);
                        }
                     break;
               }

            break;

/** UPDATE GS_SHOW_LEVEL_SCORES ******************************************************************************/
         case GS_SHOW_LEVEL_SCORES:
               if(timer.isFinished() || (keyIsPressed && ((keyCode == KEYS[KEY_FIRE]) || (keyCode == KEYS[KEY_SELECT]) || (keyCode == KEYS[KEY_NUM_5]))))
               {
                  timer.unSet();
                  
                  keyIsPressed = false;
                  keyIsReleased = false;
                  
                  timer.set(5000);
                  gameState = GS_SHOW_TOTAL_SCORES;
               }
            break;

/** UPDATE GS_SHOW_TOTAL_SCORES ************************************************************************/
         case GS_SHOW_TOTAL_SCORES:
               if(timer.isFinished() || (keyIsPressed && ((keyCode == KEYS[KEY_FIRE]) || (keyCode == KEYS[KEY_SELECT]) || (keyCode == KEYS[KEY_NUM_5]))))
               {
                  timer.unSet();
                  
                  keyIsPressed = false;
                  keyIsReleased = false;
                  
                  if(levelResult == LR_QUALIFIED)
                  {
                     nextTrack();

                  }
                  else 
                  {
                     finishTrack();
                  }
               }
            break;

/**  UPDATE GS_GAME_FINISHED  ****************************************************************************/
         case GS_GAME_FINISHED:
               if(timer.isFinished() || (keyIsPressed && ((keyCode == KEYS[KEY_FIRE]) || (keyCode == KEYS[KEY_SELECT]) || (keyCode == KEYS[KEY_NUM_5]))))
               {
                  timer.unSet();
                  
                  keyIsPressed = false;
                  keyIsReleased = false;
                  
                  finishTrack();
               }
            break;

/**  UPDATE GS_EDITOR  ****************************************************************************/
         case GS_EDITOR:

               if(keyIsPressed && ((keyCode == KEYS[KEY_LEFT]) || (keyCode == KEYS[KEY_NUM_4])))
               {
                 editorCurCol--;
                 if(editorCurCol < 0) editorCurCol = editorChars[0].length - 1;
               }
               else if(keyIsPressed && ((keyCode == KEYS[KEY_RIGHT]) || (keyCode == KEYS[KEY_NUM_6])))
                    {
                      editorCurCol++;
                      if(editorCurCol >= editorChars[0].length) editorCurCol = 0;
                    }
                    else if(keyIsPressed && ((keyCode == KEYS[KEY_UP]) || (keyCode == KEYS[KEY_NUM_2])))
                         {
                           editorCurRow--;
                           if(editorCurRow < 0) editorCurRow = editorChars.length - 1;
                         }
                         else if(keyIsPressed && ((keyCode == KEYS[KEY_DOWN]) || (keyCode == KEYS[KEY_NUM_8])))
                              {
                                editorCurRow++;
                                if(editorCurRow >= editorChars.length) editorCurRow = 0;
                              }
                              else  if(keyIsPressed && ((keyCode == KEYS[KEY_FIRE]) || (keyCode == KEYS[KEY_SELECT]) || (keyCode == KEYS[KEY_NUM_5])))
                                    {
                                      if((editorCurCol == editorChars[editorChars.length - 1].length - 1) && (editorCurRow == editorChars.length - 1))
                                      {
                                       
                                         strClear(tempStr);
                                         tempStr.append(new String(editorStr).trim());

                                         if(tempStr.length() > 0)
                                         {
                                            editorChars = null;
                                            editorStr = null;
                                            System.gc();

                                            strClear(user[USER_NAME]);
                                            user[USER_NAME].append(tempStr.toString());
                                            userWrite();

                                            gameState = GS_MENU;
                                            switch(gameSubState){
                                               case ESS_ENTER_NAME:
                                                     gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                                                  break;
                                               case ESS_EDIT_NAME:
                                                     gameSubState = menu.initMenu(GSS_MENU_OPTIONS, 1);
                                                  break;
                                            }
                                         }
                                         else
                                         {
                                            setScreen(STR_EDITOR_HINT, true, -1);
                                            wait(2000);
                                         }
                                      }
                                      else if((editorCurCol == editorChars[editorChars.length - 1].length - 2) && (editorCurRow == editorChars.length - 1))
                                           {
                                             if(editorCurrentChar > 0)
                                             {
                                               editorCurrentChar--;
                                               editorStr[editorCurrentChar] = 0;
                                             }
                                           }
                                           else
                                           {
                                             if(editorCurrentChar < editorCountChars) 
                                             {
                                               editorStr[editorCurrentChar] = editorChars[editorCurRow][editorCurCol];
                                               editorCurrentChar++;
                                             }
                                           }
                                    }

               keyIsPressed = false;
               keyIsReleased = false;
            break;
/**  UPDATE GS_ABOUT  ****************************************************************************/
         case GS_ABOUT:
         case GS_TOTAL_SCORES:
               
               if(textControl())
               {
                  gameState = GS_MENU;
                  gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                  
               }
               keyIsPressed = false;
            break;

      }
   }

/******************************************************************************/
/**  Move all objects                                                         */
/******************************************************************************/

   private void moveGameObjects()
   {
      
      long dt;
      int i, j, tInt, aPosX, aPosY, bPosX, bPosY, mode, hitedIndex;
      boolean _flag;

      switch(gameState){
         case GS_GAME:

               dt = currentVirtualTime - lastVirtualTime;
               lastVirtualTime = currentVirtualTime;
            
               explosionFirstFreeIndex = explosions.length;
               for(i = 0; i < explosions.length; i++) 
               {
                  explosions[i].update(dt);
                  if(explosions[i].isFinished() && (!explosions[i].reserved) && (i < explosionFirstFreeIndex)) explosionFirstFreeIndex = i;
               }
               
               if(isGasKeyPressing) 
               {
                  ship.increaseMainEnginePower();
               }
               else if(isGasKeyReleasing) 
                    {
                       ship.decreaseMainEnginePower();
                    }

               ship.move(dt);
               maxShipPosY = ship.posY;
               minShipPosY = ship.leftPosY;

               for(i = 0; i < npcShips.length; i++) 
               {
                  npcShips[i].npcUpdate(dt);
                  if(npcShips[i].posY > maxShipPosY) maxShipPosY = npcShips[i].posY;
                  if(npcShips[i].leftPosY < minShipPosY) minShipPosY = npcShips[i].leftPosY;
                  npcShips[i].locationAlienShip = LOCATION_NONE;
               }
               if(maxShipPosY < worldPosY) maxShipPosY = worldPosY;
               if(minShipPosY > (worldPosY - screenHeight)) minShipPosY = (worldPosY - screenHeight);

               for(i = 0; i < npcShips.length; i++)
               {
                  if(!ship.detectShipCollision(npcShips[i])) npcShips[i].detectShipCollision(ship);
                  for(j = i + 1; j < npcShips.length; j++)
                  {
                     if(!npcShips[i].detectShipCollision(npcShips[j])) npcShips[j].detectShipCollision(npcShips[i]);
                  }
               }

               shotFirstFreeIndex = shots.length;
               for(i = 0; i < shots.length; i++) 
               {
                  if(shots[i].active) 
                  {
                     if(shots[i].bY > minShipPosY && shots[i].aY < maxShipPosY)
                     {
                        shots[i].update(dt);

                        mode = 0;
                        flag = false;
                        hitedIndex = -1;

                        switch(shots[i].type){
                           case WEAPON_LASER:
                           case WEAPON_ROCKET:
                                 // Detect hit with edges
                                 //#if !(T610 || X450v2 || X450v1 || E600)
                                 for(j = shots[i].edgeFirstIndex; j < borders.length; j++)
                                 {
                                    if(borders[j].aPosY > maxShipPosY)
                                    {
                                       break;
                                    }
                                    else
                                    {
                                       if(((borders[j].type == BORDER_TRACKEDGE) || ((borders[j].type == BORDER_WALL) && (shots[i].owner.moveMode == SHIP_MODE_FLY))) && 
                                          (min(borders[j].aPosX, borders[j].bPosX) <= shots[i].aX && shots[i].aX <= max(borders[j].aPosX, borders[j].bPosX)) && 
                                          (borders[j].bPosY > shots[i].aY))
                                       {
                                          // The adge crosses with laser
                                          if(borders[j].aPosY == borders[j].bPosY && shots[i].bY >= borders[j].aPosY)
                                          {
                                             shots[i].bY = borders[j].aPosY;
                                             mode = 1;
                                             flag = true;
                                             break;
                                          }
                                          else
                                          {
                                             if(isIntersection(shots[i].aX, shots[i].aY - 1, shots[i].bX, shots[i].bY + 1, borders[j].aPosX, borders[j].aPosY, borders[j].bPosX, borders[j].bPosY))
                                             {
                                                tInt = getCrossPoint(shots[i].aX, shots[i].aY, shots[i].bX, shots[i].bY, borders[j].aPosX, borders[j].aPosY, borders[j].bPosX, borders[j].bPosY);
                                                tInt = (tInt & 0x0000ffff);
                                                //if(tInt <= shots[i].bY && tInt >= shots[i].aY) 
                                                if(tInt <= shots[i].bY) 
                                                {
                                                   shots[i].bY = tInt;
                                                   mode = 1;
                                                   flag = true;
                                                }
                                                break;
                                             }
                                          }
                                       }
                                    }
                                 }
                                 //#endif

                                 // Detect hit with track's items
                                 posY = worldPosY + TRACK_ITEM_HEIGHT;
                                 for(j = shots[i].itemFirstIndex; (j < trackItems.length) && (trackItems[j].y <= posY); j++)
                                 {
                                    if(GameScreen.trackItems[j].visible) 
                                    {
                                       aPosX = trackItems[j].x;
                                       aPosY = trackItems[j].y;
                                       bPosX = trackItems[j].x + TRACK_ITEM_WIDTH;
                                       bPosY = trackItems[j].y - TRACK_ITEM_HEIGHT;
                                       if(aPosX <= shots[i].aX && shots[i].aX <= bPosX && shots[i].aY <= aPosY && shots[i].bY >= bPosY)
                                       {
                                          tInt = (aPosY + bPosY) >> 1;
                                          //if(tInt <= shots[i].bY && tInt >= shots[i].aY)
                                          if(tInt <= shots[i].bY)
                                          {
                                             shots[i].bY = tInt;
                                             hitedIndex = j;
                                             mode = 2;
                                             flag = true;
                                          }
                                          break;
                                       }
                                    }
                                 }

                                 //Detect hit with bombs and mines
                                 for(j = 0; j < shots.length ; j++) 
                                 {
                                    if(shots[j].active && (j != i))
                                    {
                                       switch(shots[j].type){
                                          case WEAPON_BOMB:
                                                aPosX = shots[j].aX ;
                                                aPosY = shots[j].aY + (BOMB_HEIGHT >> 1);
                                                bPosX = shots[j].bX;
                                                bPosY = shots[j].bY - (BOMB_HEIGHT >> 1);
                                                _flag = true;
                                             break;
                                          case WEAPON_MINE:
                                                aPosX = shots[j].stepY - (BOMB_WIDTH >> 1);
                                                aPosY = shots[j].aY + (BOMB_HEIGHT >> 1);
                                                bPosX = shots[j].stepY + (BOMB_WIDTH >> 1);
                                                bPosY = shots[j].bY - (BOMB_HEIGHT >> 1);
                                                _flag = true;
                                             break;
                                          default:
                                                aPosX = aPosY = bPosX = bPosY = 0;
                                                _flag = false;
                                             break;
                                       }
                                       if(_flag && aPosX <= shots[i].aX && shots[i].aX <= bPosX && shots[i].aY <= aPosY && shots[i].bY >= bPosY)
                                       {
                                          tInt = (aPosY + bPosY) >> 1;
                                          //if(tInt <= shots[i].bY && tInt >= shots[i].aY)
                                          if(tInt <= shots[i].bY)
                                          {
                                             shots[i].bY = tInt;
                                             hitedIndex = j;
                                             mode = 4;
                                             flag = true;
                                          }
                                          break;
                                       }
                                    }
                                 }


                                 // Detect hit with ships
                                 if((ship != shots[i].owner) && shots[i].detectShipHit(ship))
                                 {
                                    if(ship.leftPosY <= shots[i].bY)
                                    {
                                       shots[i].bY = ship.leftPosY;
                                       hitedIndex = 0;
                                       mode = 3;
                                       flag = true;
                                    }
                                 }
                                 else
                                 {
                                    for(j = 0; j < npcShips.length; j++)
                                    {
                                       if((npcShips[j] != shots[i].owner) && shots[i].detectShipHit(npcShips[j]))
                                       {
                                          if(npcShips[j].leftPosY <= shots[i].bY)
                                          {
                                             shots[i].bY = npcShips[j].leftPosY;
                                             hitedIndex = j + 1;
                                             mode = 3;
                                             flag = true;
                                             break;
                                          }
                                       }
                                    }
                                 }
                              break;
                           case WEAPON_BOMB:
                                 if(shots[i].counter <= 0)
                                 {
                                    aPosX = shots[i].aX - EXPLOSION_AREA;
                                    aPosY = shots[i].aY + EXPLOSION_AREA;
                                    bPosX = shots[i].bX + EXPLOSION_AREA;
                                    bPosY = shots[i].bY - EXPLOSION_AREA;
                                    if(aPosX < ship.rightPosX && bPosX > ship.leftPosX && bPosY < ship.posY && aPosY > ship.leftPosY)
                                    {
                                       ship.changeHealth(WEAPON_DAMAGE[WEAPON_BOMB]);
                                    }
                                    for(j = 0; j < npcShips.length; j++)
                                    {
                                       if(aPosX < npcShips[j].rightPosX && bPosX > npcShips[j].leftPosX && bPosY < npcShips[j].posY && aPosY > npcShips[j].leftPosY)
                                       {
                                          npcShips[j].changeHealth(WEAPON_DAMAGE[WEAPON_BOMB]);
                                       }
                                    }
                                    flag = true;
                                    break;
                                 }
                           case WEAPON_MINE:
                                 // Detect hit with ships
                                 if((ship != shots[i].owner) && (ship.detectCollosionWithLine(shots[i].aX, shots[i].aY, shots[i].bX, shots[i].bY) > -1))
                                 {
                                    hitedIndex = 0;
                                    mode = 3;
                                    flag = true;
                                 }
                                 else
                                 {
                                    for(j = 0; j < npcShips.length; j++)
                                    {
                                       if((npcShips[j] != shots[i].owner) && (npcShips[j].detectCollosionWithLine(shots[i].aX, shots[i].aY, shots[i].bX, shots[i].bY) > -1))
                                       {
                                          hitedIndex = j + 1;
                                          mode = 3;
                                          flag = true;
                                          break;
                                       }
                                    }
                                 }
                              break;
                        }

                        if(flag)
                        {
                           switch(shots[i].type){
                              case WEAPON_LASER:
                                    if((shots[i].explosionIndex < explosions.length) && explosions[shots[i].explosionIndex].isFinished())
                                    {
                                       //#if S40v1
                                       addExplosion(shots[i].explosionIndex, A_EXPLOSION, shots[i].bX, shots[i].bY);
                                       //#else
                                       addExplosion(shots[i].explosionIndex, A_EXPLOSION_SMALL, shots[i].bX, shots[i].bY);
                                       //#endif
                                    }
                                 break;
                              case WEAPON_MINE:
                                    //#if S40v1
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION, shots[i].stepY, shots[i].bY);
                                    //#else
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION_BIG, shots[i].stepY, shots[i].bY);
                                    //#endif
                                    shots[i].deactivate();
                                 break;
                              case WEAPON_BOMB:
                                    //#if S40v1
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION, shots[i].bX - EXPLOSION_DISTANCE, shots[i].bY);
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION, shots[i].bX + EXPLOSION_DISTANCE, shots[i].bY);
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION, shots[i].bX, shots[i].bY - EXPLOSION_DISTANCE);
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION, shots[i].bX, shots[i].bY + EXPLOSION_DISTANCE);
                                    //#else
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION_BIG, shots[i].bX - EXPLOSION_DISTANCE, shots[i].bY);
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION_BIG, shots[i].bX + EXPLOSION_DISTANCE, shots[i].bY);
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION_BIG, shots[i].bX, shots[i].bY - EXPLOSION_DISTANCE);
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION_BIG, shots[i].bX, shots[i].bY + EXPLOSION_DISTANCE);
                                    //#endif
                                    shots[i].deactivate();
                                 break;
                              default:
                                    //#if S40v1
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION, shots[i].bX, shots[i].bY);
                                    //#else
                                    addExplosion(explosionFirstFreeIndex, A_EXPLOSION_SMALL, shots[i].bX, shots[i].bY);
                                    //#endif
                                    shots[i].deactivate();
                                 break;
                           }

                           switch(mode){
                              case 1: // edge was hited
                                 break;
                              case 2: // track's item was hited
                                    if(hitedIndex < trackItems.length) trackItems[hitedIndex].visible = false;
                                 break;
                              case 3: // ship was hited
                                    switch(hitedIndex){
                                       case 0:
                                             ship.changeHealth(WEAPON_DAMAGE[shots[i].type]);
                                          break;
                                       default:
                                             if((hitedIndex - 1) < npcShips.length) npcShips[hitedIndex - 1].hitWeapon(shots[i].type);
                                          break;
                                    }
                                 break;
                              case 4: // Other shot was hited
                                    if(hitedIndex < shots.length) shots[hitedIndex].deactivate();
                                 break;
                           }
                        }
                     } 
                     else 
                     {
                        shots[i].deactivate();
                     }
                  }
                  else if(i < shotFirstFreeIndex) shotFirstFreeIndex = i;
               }

               switch(ship.shipState){
                  case SHIP_STATE_MOVE:
                  case SHIP_STATE_DESTROYED:
                  case SHIP_STATE_REINIT:
                        ship.racingTime = System.currentTimeMillis() - timeStartGame;
                        if(ship.posY >= trackLength)
                        {
                           place = 1;
                           for(i = 0; i < npcShips.length; i++) 
                           {
                              if((npcShips[i].shipState == SHIP_STATE_FINISH || npcShips[i].shipState == SHIP_STATE_STOP) && (npcShips[i].racingTime < ship.racingTime))
                              {
                                 place++;
                              }
                           }

                           tInt = STR_END_RACE;
                           switch(place){
                              case 1:
                                    ship.money += 3000;
                                    showNote(STR_FIRST_PLACE, 2000);
                                    levelResult = LR_QUALIFIED;
                                    tInt = STR_NEXT_TRACK;
                                    ship.money += 3000;
                                    //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                                       soundPlay(SOUND_FIRST_PLACE);
                                    //#endif                                                       
                                 break;
                              case 2:
                                    ship.money += 2000;
                                    showNote(STR_SECOND_PLACE, 2000);
                                    levelResult = LR_FAILED;
                                    //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                                       soundPlay(SOUND_GAME_OVER);
                                    //#endif                                                       
                                 break;
                              case 3:
                                    ship.money += 750;
                                    showNote(STR_THIRD_PLACE, 2000);
                                    levelResult = LR_FAILED;
                                    //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                                       soundPlay(SOUND_GAME_OVER);
                                    //#endif                                                       
                                 break;
                           }
                           if(strings[STR_MENU_REPLAY] != null)
                           {
                              i = strings[STR_MENU_REPLAY].toString().indexOf('|');
                              j = strings[STR_MENU_REPLAY].toString().indexOf('|', i + 1);
                              if(i > -1 && j > -1)
                              {
                                 strings[STR_MENU_REPLAY].delete(i + 1, j);
                              }
                              if(strings[tInt] != null) strings[STR_MENU_REPLAY].insert(i + 1, strings[tInt].toString());
                           }

                           ship.shipState = SHIP_STATE_FINISH;
                        }
                     break;
                  case SHIP_STATE_FINISH:
                        if(ship.leftPosY > trackLength)
                        {
                           ship.stopTurnEngine(SHIP_TURNSTATE_FREE);
                           ship.startBrakeEngine(ship.getBrakeForce((FL_COUNTTILES * TILE_HEIGHT) << 1));
                           ship.shipState = SHIP_STATE_STOP;
                           ship.aBody.startAnimation(SHIP_FREE_ANIMATIONS[ship.type][ship.bodyState], ANIMATION_PLAY_REPEAT);
                        }
                        else if(ship.V == 0) ship.shipState = SHIP_STATE_STOP;
                     break;
                  case SHIP_STATE_STOP:
                        if(timer.isFinished())
                        {
                           hideNote();

                           levelTime = ship.racingTime;
                           levelScores = ship.money;
                           tInt = 0;
                           if(levelBonusTime - ship.racingTime > 0)
                           {
                              tInt = fpToInt(fpMul(fpToFP(levelBonusTime - ship.racingTime), FP_1000));
                           }
                           levelBonus = (tInt * BONUS_SCORES_PER_SECONDS);
                           levelResultScores = levelBonus + levelScores;

                           if(levelResult == LR_QUALIFIED)
                           {
                              if((groupCurrent == settings[SETTINGS_GROUP]) && (levelCurrent == settings[SETTINGS_LEVEL]))
                              {
                                 settings[SETTINGS_LEVEL]++;
                                 if(settings[SETTINGS_LEVEL] >= levelsCount)
                                 {
                                    settings[SETTINGS_LEVEL] = 0;
                                    settings[SETTINGS_GROUP]++;
                                 }
                                 writeSettings(settings, RMS_SETTINGS);
                              }
                           }

                           menu.initMenu(GSS_MENU_REPLAY, 1);
                           gameSubState = GSS_GAME_FINISHED;
                        }
                     break;
               }

               if(roadState == RS_MOVE)
               {
                  worldStepX = ship.stepX;
                  if((worldPosY - ship.posY) <= SCREEN_SHIP_POSITION)
                  {
                     worldStepY = ship.stepY;
                  }
                  else
                  {
                     worldStepY = 0;
                  }

                  //#if Galaxy
                     starsStepX -= worldStepX;
                     if(starsStepX < 0)
                     {
                        starsOffSetX = (-starsStepX) >> 3;
                        starsOffSetX = -starsOffSetX;
                     }
                     else starsOffSetX = starsStepX >> 3;
                     if(starsOffSetX != 0) starsStepX = 0;

                     starsStepY += worldStepY;
                     starsOffSetY = starsStepY >> 3;
                     if(starsOffSetY != 0) starsStepY = 0;

                     for(i = 0; i < stars.length; i++)
                     {
                        j = (stars[i] >> 24) & 0x000000FF;
                        posX = ((stars[i] >> 12) & 0x000FFF) + starsOffSetX;
                        posY = (stars[i] & 0x000FFF) + starsOffSetY;

                        if(posX > (screenWidth + STARS_TILE_WIDTH)) posX = 0;
                        else if(posX < 0) posX = screenWidth;

                        if(posY > (screenHeight + STARS_TILE_HEIGHT)) posY = 0;

                        stars[i] = ((j << 24) & 0xFF000000) | ((posX << 12) & 0x00FFF000) | (posY & 0x00000FFF);
                     }
                  //#endif

                  worldPosX -= worldStepX;
                  worldPosY += worldStepY;
                  if(worldPosY >= worldLength)
                  {
                     trackOffSetY +=  worldStepY - (worldPosY - worldLength);
                     worldPosY = worldLength;
                     
                     roadState = RS_STOP;
                  }
                  else
                  {
                     trackOffSetY += worldStepY;
                     tInt = trackOffSetY / TILE_HEIGHT;
                     if(tInt > 0)
                     {
                        if(tfeRepetition > tInt)
                        {
                           tfePosY += TILE_HEIGHT * tInt;
                           tfeRepetition -= tInt;
                        }
                        else
                        {
                           trackCurrentRow += tInt;
                           tfeRepetition = track[trackCurrentRow].repetition;
                           tfePosY = track[trackCurrentRow].posY;
                        }
                        trackOffSetY -= tInt * TILE_HEIGHT;
                     }
                  }

                  // Correct index of first track's item
                  for(; (firstTrackItem < trackItems.length) && (trackItems[firstTrackItem].y < (worldPosY - screenHeight)); firstTrackItem++);

               }

               switch(gameSubState){
                  case GSS_GAME_PLAY:
                        if(timer.isFinished())
                        {
                           hideNote();
                        }

                     break;
                  case GSS_GAME_BONUS_TIME:
                        if(timer.isFinished())
                        {
                           hideNote();

                           keyIsPressed = false;
                           keyIsReleased = false;
                           
                           showNote(STR_READY, 2500);
                           gameSubState = GSS_GAME_READY;
                        }
                     break;
                  case GSS_GAME_READY:
                        if(timer.isFinished())
                        {
                           hideNote();

                           keyIsPressed = false;
                           keyIsReleased = false;
                           
                           gameSubState = GSS_GAME_PLAY;
                           roadState = RS_MOVE;
                           
                           isGasKeyReleasing = isGasKeyPressing = false;
                           ship.shipState = SHIP_STATE_MOVE;
                           ship.aBody.startAnimation(SHIP_ANIMATIONS[ship.type][ship.bodyState], ANIMATION_PLAY_REPEAT);

                           for(i = 0; i < npcShips.length; i++) npcShips[i].npcStartRacing();

                           cheatCode = 0;
                          
                           showNote(STR_GO, 2000);

                           //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                              soundPlay(SOUND_GO);
                           //#endif
                           
                           timeStartGame = System.currentTimeMillis();
                        }
                     break;
//------------------------------------------------------------------------------------------------//
               }
            break;
      }
   }

////////////////////////////////////////////////////////////////////////////////////////////////////

   public void moveObjects() 
   {
      int i;
      switch(gameState){
// MOVE GS_LOGO ****************************************************************************//
         case GS_LOGO:
               if(timer.isFinished())
               {
                  timer.unSet();

                  imgUnLoad(IMG_LOGO);
                  System.gc();
                  
                  keyIsPressed = false;
                  keyIsReleased = false;

                  //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                     gameState = GS_MENU;
                     gameSubState = menu.initMenu(GSS_MENU_SOUND_STARTUP, 1);
                  //#else
                     //#if !FULL_CANVAS
                        removeAllCmds();
                     //#endif
                     timer.set(3000);
                     gameState = GS_SPLASH;
                  //#endif
               }
            break;

// MOVE GS_SPLASH ****************************************************************************//
         case GS_SPLASH:
               if(timer.isFinished())
               {
                  timer.unSet();
                  keyIsPressed = false;
                  keyIsReleased = false;
                  
                  if(user[USER_NAME].length() > 0)
                  {
                     gameState = GS_MENU;
                     gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                  }
                  else
                  {
                     setScreen(STR_FIRST_RUNING, true, -1);
                     wait(5000);

                     keyIsPressed = false;

                     editorInit(EDITOR_NAME_CHARS);

                     gameState = GS_EDITOR;
                     gameSubState = ESS_ENTER_NAME;
                  }
               }
            break;

// Move GS_MENU **********************************************************************************/
         case GS_SELECTSHIP:

               ssOldShipPosX += ssStep;
               ssCurrentShipPosX += ssStep;

               if(abs((screenWidth >> 1) - ssCurrentShipPosX) < abs(ssStep)) 
               {
                  ssStep = 0;
                  shipBodyState = (byte)(SHIP_ANIMATIONS[PLAYER_SHIPS[shipCurrent]].length >> 1);
                  ssCurrentShipAnim.changeAnimation(SHIP_ANIMATIONS[ssCurrentShip][shipBodyState]);
                  ssOldShipAnim.changeAnimation(SHIP_ANIMATIONS[ssOldShip][shipBodyState]);
               }

               if(ssCurrentShipAnim != null && ssCurrentShipAnim != null) 
               {
                  ssCurrentShipAnim.updateAnimation(System.currentTimeMillis() - currentRealTime);
                  ssOldShipAnim.updateAnimation(System.currentTimeMillis() - currentRealTime);
                  currentRealTime = System.currentTimeMillis();
               }

            break;

// Move GS_GAME **********************************************************************************/
         case GS_GAME:
               switch(gameSubState){
                  case GSS_GAME_PLAY:
                  case GSS_GAME_BONUS_TIME:
                  case GSS_GAME_READY:
                        currentRealTime = System.currentTimeMillis() - timeStartLoop;
                        while(timeSchduledTask <= currentRealTime)
                        {
                           currentVirtualTime = timeSchduledTask;

                           //updateGameObjects();
                           moveGameObjects();

                           timeSchduledTask += TASK_TIME;
                        }
                        currentVirtualTime = currentRealTime;
                     break;
               }
            break;
         case GS_INTERNET:
               switch(gameSubState){
//****************************************************************************************************
                  //#if mp
// Move GS_INTERNET **********************************************************************************/
                  /********************************************************************************/
                  case GSS_INTERNET_DLLEVELS:
                        
                        boolean f1, f2, f3;

                        f1 = f2 = f3 = true;
                        
                        if(settings[SETTINGS_DL_INF] != groupCurrent)
                        {
                           //f1 = rmsWrite(downloadFile(midlet.getAppProperty("DatResource-URL") + (groupCurrent + 1) + "_inf.bin"), RMS_LEVELS_INF);
                           f1 = rmsWrite(downloadFile(DatResourceURL + (groupCurrent + 1) + "_inf.bin"), RMS_LEVELS_INF);
                           if(f1)
                           {
                              settings[SETTINGS_DL_INF] = (byte)groupCurrent;
                              writeSettings(settings, RMS_SETTINGS);
                           }
                        }

                        if(settings[SETTINGS_DL_SPECS] != groupCurrent)
                        {
                           //f2 = rmsWrite(downloadFile(midlet.getAppProperty("BinResource-URL") + (groupCurrent + 1) + "_spec.bin"), RMS_LEVELS_SPECS);
                           f2 = rmsWrite(downloadFile(BinResourceURL + (groupCurrent + 1) + "_spec.bin"), RMS_LEVELS_SPECS);
                           if(f2)
                           {
                              settings[SETTINGS_DL_SPECS] = (byte)groupCurrent;
                              writeSettings(settings, RMS_SETTINGS);
                           }
                        }

                        if(settings[SETTINGS_DL_BIN] != groupCurrent)
                        {
                           //f3 = rmsWrite(downloadFile(midlet.getAppProperty("BinResource-URL") + Integer.toString(groupCurrent + 1) + ".bin"), RMS_LEVELS_BIN);
                           f3 = rmsWrite(downloadFile(BinResourceURL + Integer.toString(groupCurrent + 1) + ".bin"), RMS_LEVELS_BIN);
                           if(f3)
                           {
                              settings[SETTINGS_DL_BIN] = (byte)groupCurrent;
                              writeSettings(settings, RMS_SETTINGS);
                           }
                        }

                        gameState = GS_MENU;
                        if(f1 && f2 && f3)
                        {
                           updateMutablePartOfIntro();
                           gameSubState = menu.initMenu(GSS_MENU_RMS_LEVELS, 1);
                        }
                        else
                        {
                           setScreen(STR_LEVELS_DL_ERROR, true, -1);
                           wait(3000);
                           gameSubState = menu.initMenu(GSS_MENU_GROUPS, groupCurrent + 1);
                        }
                     break;

/********************************************************************************/
                  case GSS_INTERNET_DL_UPDATE:

                        strClear(tempResStr);
                        tempResStr.append(groupHash);

                        if(rmsWrite(downloadFile(DatResourceURL + "sr_inf.bin"), RMS_GROUP_INF))
                        {
                           setScreen(STR_UPDATING, true, -1);

                           updateMutablePartOfIntro();

                           i = getAbsoluteLevelNumber(groups.length - 1, groups[groups.length - 1].levelsCount);
                           if(i > settings[SETTINGS_COUNT_LEVELS]) 
                           {
                              settings[SETTINGS_COUNT_LEVELS] = (byte)i;
                              
                              passedLevels = null;
                              System.gc();
                              passedLevels = new byte[settings[SETTINGS_COUNT_LEVELS]];
                           }
                           
                           writeSettings(settings, RMS_SETTINGS);
                           
                           if(groupHash.toString().equals(tempResStr.toString()))
                           {
                              setScreen(STR_UPDATE_OK, true, -1);
                              wait(3000);
                           }
                           else
                           {
                              setScreen(STR_UPDATE_IS_UP_TO_DATE, true, -1);
                              wait(3000);
                           }
                        }
                        else
                        {
                              setScreen(STR_UPDATE_FAILED, true, -1);
                              wait(3000);
                        }
                        
                        gameState = GS_MENU;
                        gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);

                     break;
                  //#endif

                  /********************************************************************************/
                  case GSS_INTERNET_DL_TOTAL_SCORES:
                        if(doPost(MODE_DL_TOTAL_SCORES, 0, 0, 0) == CS_SUCCESSFUL)
                        {
                           textInit(STR_SCORES, TEXT_OFFSET << 1, fontHeight + (TEXT_OFFSET << 1), screenWidth - (TEXT_OFFSET << 2), screenHeight - fontHeight - (TEXT_OFFSET << 2), TEXT_LEFT);
                           gameState = GS_TOTAL_SCORES;
                        }
                        else
                        {
                           gameState = GS_MENU;
                           gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                        }
                     break;

                  /********************************************************************************/
                  case GSS_INTERNET_UL_TOTAL_SCORES:
                        if(doPost(MODE_UL_TOTAL_SCORES, levelTotalResultScores, levelTotalTime, levelTotalScores) == CS_SUCCESSFUL)
                        {
                           if(place > 0)
                           {
                              setPlace(place);
                              setScreen(STR_PLACE, true, -1);
                              wait(5000);
                           }

                           if(levelResult == LR_FAILED)
                           {
                              setScreen(STR_GAME_OVER, true, -1);
                              wait(3000);
                           }
                           gameState = GS_MENU;
                           gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
                        }
                        else
                        {
                           gameState = GS_MENU;
                           gameSubState = menu.initMenu(GSS_MENU_TOTAL_RETRY, 1);
                        }
                     break;
               }
            break;
      }
   }

////////////////////////////////////////////////////////////////////////////////
   
   private void nextTrack()
   {
      int i;
      switch(levelResult){
         case LR_QUALIFIED:

               i = getAbsoluteLevelNumber(groupCurrent, levelCurrent);
               if(i < passedLevels.length) 
               {
                  passedLevels[i] = 1;
               }

               levelCurrent++;
               if(levelCurrent >= groups[groupCurrent].levelsCount)
               {
                  levelCurrent = 0;
                  groupCurrent++;
                  if(groupCurrent >= groups.length)
                  {
                     // All tracks finished
                     groupCurrent = groups.length - 1;
                     levelCurrent = groups[groupCurrent].levelsCount - 1;

                     textInit(STR_WINER_TEXT, TEXT_OFFSET, TEXT_OFFSET, screenWidth - (TEXT_OFFSET << 1), screenHeight - (TEXT_OFFSET << 1), TEXT_CENTER);
                     
                     timer.unSet();
                     timer.set(5000);
                     //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                        soundPlay(SOUND_END_GAME);
                     //#endif                                                       
                     gameState = GS_GAME_FINISHED;
                     return;
                  }
               }

               gameState = GS_MENU;
               if(groupCurrent < COUNT_LEVELS_IN_JAR)
               {
                  strClear(strings[STR_MENU_JAR_LEVELS]);
                  strings[STR_MENU_JAR_LEVELS].append(getLevelString(groupCurrent));
                  gameSubState = menu.initMenu(GSS_MENU_JAR_LEVELS, levelCurrent + 1);
               }
               else if(groupCurrent == settings[SETTINGS_DL_INF] && groupCurrent == settings[SETTINGS_DL_SPECS] && groupCurrent == settings[SETTINGS_DL_BIN ])
                    {
                       gameSubState = menu.initMenu(GSS_MENU_RMS_LEVELS, levelCurrent + 1);
                    }
                    else
                    {
                       gameSubState = menu.initMenu(GSS_MENU_GROUPS, groupCurrent + 1);
                    }
            break;

         case LR_FAILED:
               finishTrack();
            break;
      }
   }

   private void finishTrack()
   {
      gameState = GS_MENU;
      if(levelTotalResultScores > 0)
      {
         gameSubState = menu.initMenu(GSS_MENU_UL_TOTAL_SCORES, 1);
      }
      else
      {
         if(levelResult == LR_FAILED)
         {
            setScreen(STR_GAME_OVER, true, -1);
            wait(3000);
         }
         gameSubState = menu.initMenu(GSS_MENU_MAIN, 1);
      }
   }

/**************************************************************************************************/

/**************************************************************************************************/

   private void drawShip(Ship ship)
   {
      if(ship.shipVisible) 
      {
         drawFrameset(ship.aBody.getFrameSet(), worldPosX + ship.posX, worldPosY - ship.posY);
         if(ship.healthVisible) 
         {
            posX = worldPosX + ship.posX;
            posY = worldPosY - ship.leftPosY + 5;
            drawFrame(FRAMES[F_HEALTH_METER_BG], posX, posY, 0, 0);
            drawFrame(FRAMES[F_HEALTH_METER], posX, posY, ship.healthMeterWidth, 0);
         }
         if(ship.shieldActive)
         {
            drawFrameset(ship.aShield.getFrameSet(), worldPosX + ship.posX, worldPosY - ship.posY);
         }
      }
   }

/******************************************************************************/
/**  Draw all objects                                                         */
/******************************************************************************/

   public void drawObjects(Graphics g) 
   {
      int i, l, j, tInt = 0, tIntRes, x, y;
      long tLong;

      if(isPainting) return;
      isPainting = true;

      //#if Nokia && (S30 || S40v1 || S40v2 || N6235)
         if(timeNextSetLights <= System.currentTimeMillis())
         {
            //DeviceControl.setLights(0, 100);
            timeNextSetLights = System.currentTimeMillis() + SETLIGHTS_TIME;
         }
      //#endif

      gd = g;

      switch(gameState){
// DRAW GS_LOGO ***********************************************************************************/
         case GS_LOGO:
               fillBG(UI_LogoBGColor, 0, 0, screenWidth, screenHeight);
               drawFrame(FRAMES[F_LOGO], screenWidth >> 1, screenHeight >> 1, 0, 0);
            break;

// DRAW GS_SPLASH *********************************************************************************/
         case GS_SPLASH:
         case GS_MENU:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);
               //#if S40v1
                  drawFrameset(FS_SPLASH, screenWidth >> 1, screenHeight >> 1);
               //#elif GX20 || S40v3big || S60v3 || S700 || E1000 || E71 || MM5600 || A900 || N6265 || VI2300 || RL4920 || A680 || NX225 || TX95c || S3100 || PM8200
                  if(images[IMG_SPLASH] != null) 
                  {
                     g.drawImage(images[IMG_SPLASH], (screenWidth - images[IMG_SPLASH].getWidth()) >> 1, (screenHeight - images[IMG_SPLASH].getHeight()) >> 1, 0);
                  }
               //#else
                  drawFrame(FRAMES[F_SPLASH], screenWidth >> 1, screenHeight >> 1, 0, 0);
               //#endif
               if(gameState == GS_MENU)
               {
                  //#if !(GX20 || T610)
                  drawRaster();
                  //#endif
                  menu.drawMenu();
               }
            break;

// Draw GS_MENU **********************************************************************************/
         case GS_SELECTSHIP:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);
               
               g.setColor(0x444444);
               g.fillRoundRect(ssShipAreaX1, ssShipAreaY1, ssShipAreaX2 - ssShipAreaX1, ssShipAreaY2 - ssShipAreaY1, 15, 15);
               
               drawFrameset(ssCurrentShipAnim.getFrameSet(), ssCurrentShipPosX, (SELECTSHIP_SHIP_AREA_HEIGHT - SELECTSHIP_SHIP_MAX_HEIGHT) >> 1);
               if(ssStep != 0) drawFrameset(ssOldShipAnim.getFrameSet(), ssOldShipPosX, (SELECTSHIP_SHIP_AREA_HEIGHT - SELECTSHIP_SHIP_MAX_HEIGHT) >> 1);

               fillBG(UI_BGColor, 0, ssShipAreaY1, ssShipAreaX1, ssShipAreaY2 - ssShipAreaY1);
               fillBG(UI_BGColor, ssShipAreaX2, ssShipAreaY1, screenWidth - ssShipAreaX2, ssShipAreaY2 - ssShipAreaY1);

               setClip(0, 0, screenWidth, screenHeight);
               g.setColor(0xFFFFFF);
               g.drawRoundRect(ssShipAreaX1, ssShipAreaY1, ssShipAreaX2 - ssShipAreaX1, ssShipAreaY2 - ssShipAreaY1, 15, 15);
               
               if(shipCurrent > 0) 
               {
                  drawFrame(FRAMES[F_ARROW_LEFT], ssShipAreaX1 >> 1, ssShipAreaY1 + ((ssShipAreaY2 - ssShipAreaY1) >> 1), 0, 0);
               }
               if(shipCurrent < (PLAYER_SHIPS.length - 1)) 
               {
                  drawFrame(FRAMES[F_ARROW_RIGHT], ssShipAreaX2 + ((screenWidth - ssShipAreaX2) >> 1), ssShipAreaY1 + ((ssShipAreaY2 - ssShipAreaY1) >> 1), 0, 0);
               }

               menu.drawMenu();
               
               if(flag) 
               {
                  textDraw(TEXT_BORDER);
               }
            break;

// Draw GS_MENU **********************************************************************************/
         case GS_GAME:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);

               //#if Galaxy
                  //drawFrame(FRAMES[F_GALAXY], screenWidth >> 1, screenHeight >> 1, 0, 0);
                  for(i = 0; i < stars.length; i++)
                  {
                     tInt = (stars[i] >> 24) & 0x000000FF;
                     posX = (stars[i] >> 12) & 0x00000FFF;
                     posY = stars[i] & 0x00000FFF;
                     //if(tInt < images.length && images[tInt] != null) g.drawImage(images[tInt], posX - STARS_TILE_WIDTH, posY - STARS_TILE_HEIGHT, 0);
                     if(tInt < FRAMES.length) drawFrame(FRAMES[tInt], posX, posY, 0, 0);
                  }
                  setClip(0, 0, screenWidth, screenHeight);
               //#endif

               l = trackCurrentRow;
               j = 0;
               tIntRes = -trackOffSetY;
               posY = worldPosY - tfePosY;
               tceRepetition = tfeRepetition;
               while(tIntRes < screenHeight)
               {
                  posX = worldPosX + track[l].posX;
                  posY -= TILE_HEIGHT;
                  for(i = 0; i < track[l].tiles.length && posX < screenWidth; i++)
                  {
                     tInt = posX + TILE_WIDTH;
                     //if((track[l].tiles[i] > -1) && (((posX >= 0) && (posX <= screenWidth)) || ((tInt >= 0) && (tInt <= screenWidth))))
                     if((track[l].tiles[i] > -1) && (posX >= 0 || tInt >= 0))
                     {
                        g.drawImage(images[track[l].tiles[i]], posX, posY, 0);
                     }
                     posX += TILE_WIDTH;
                  }

                  tIntRes += TILE_HEIGHT;
                  j++;
                  if(j >= tceRepetition)
                  {
                     j = 0;
                     l++;
                     if(l < track.length) tceRepetition = track[l].repetition;
                  }
               }

               posY = worldPosY + TRACK_ITEM_HEIGHT;
               for(i = firstTrackItem; (i < trackItems.length) && (trackItems[i].y < posY); i++)
               {
                  if(trackItems[i].visible) 
                  {
                     posX = worldPosX + trackItems[i].x;
                     if((0 < (posX + TRACK_ITEM_WIDTH)) && (screenWidth > posX))
                     {
                        g.drawImage(images[trackItems[i].type], posX, worldPosY - trackItems[i].y, 0);
                     }
                  }
               }

               for(i = 0; i < shots.length; i++) 
               {
                  posX = worldPosX + shots[i].aX;
                  posY = worldPosY - shots[i].aY;
                  if(shots[i].active && 0 < posY && posY < screenHeight && -5 < posX && posX < (screenWidth + 5))
                  {
                     switch(shots[i].type){
                        case WEAPON_LASER:
                              posY = worldPosY - shots[i].bY;
                              if(posY < 0) 
                              {
                                 posY = 0;
                                 tInt = worldPosY - shots[i].aY;
                              }
                              else 
                              {
                                 tInt = shots[i].bY - shots[i].aY;
                              }
                              if(setClip(posX - 2, posY, 4, tInt)) g.drawImage(imgLaser, posX - 2, posY, 0);
                           break;
                        case WEAPON_ROCKET:
                              drawFrameset(shots[i].getFrameSet(), worldPosX + shots[i].bX, worldPosY - shots[i].bY);
                           break;
                        case WEAPON_BOMB:
                              drawFrameset(shots[i].getFrameSet(), worldPosX + ((shots[i].aX + shots[i].bX) >> 1), worldPosY - shots[i].bY);
                           break;
                        case WEAPON_MINE:
                              posX = worldPosX + shots[i].aX;
                              if(posX < 0) posX = 0;
                              if(setClip(posX, posY - 2, shots[i].bX - shots[i].aX, 4)) g.drawImage(imgSensor, posX, posY - 2, 0);
                              drawFrameset(FS_MINE, worldPosX + shots[i].stepY, worldPosY - shots[i].aY);
                           break;
                     }
                  }
               }

               for(i = 0; i < 2; i++)
               {
                  if(ship.moveMode == i) drawShip(ship);

                  for(j = 0; j < npcShips.length; j++) 
                  {
                     if(npcShips[j].moveMode == i) drawShip(npcShips[j]);
                  }
               }


               for(i = 0; i < explosions.length; i++) 
               {
                  if(explosions[i].state == EXPLOSION_STATE_ACTIVE) drawFrameset(explosions[i].getFrameSet(), worldPosX + explosions[i].x, worldPosY - explosions[i].y);
               }

               //#if !(T610 || X450v2 || X450v1 || E600)
               drawTime(ship.racingTime, ICON_SPACING, ICON_SPACING, LEFT_TO_RIGHT);
               drawString(ship.money, screenWidth - ICON_SPACING, ICON_SPACING, RIGHT_TO_LEFT);
               //#endif

               if(ship.itemType == ITEM_WEAPON && ship.weaponCount > 0)
               {
                  posY = fontHeight + (ICON_SPACING << 1);
                  drawFrame(FRAMES[WEAPON_IMG[ship.weaponType]], ICON_SPACING, posY, 0, 0);
                  if(ship.weaponCount > 1 && ship.weaponType != WEAPON_LASER) 
                  {
                     drawString(ship.weaponCount, TRACK_ITEM_WIDTH + (ICON_SPACING << 1), posY + ((TRACK_ITEM_WIDTH - fontHeight) >> 1), RIGHT_TO_LEFT);
                  }
               }

               if(ship.itemType == ITEM_POWERUP && ship.powerupCount > 0)
               {
                  posY = fontHeight + (ICON_SPACING << 1);
                  switch(ship.powerupType){
                     case SPECIALITEM_SHIELD:
                           drawFrame(FRAMES[F_ICON_SHIELD], ICON_SPACING, posY, 0, 0);
                        break;
                     case SPECIALITEM_NITRO:
                           drawFrame(FRAMES[F_ICON_NITRO], ICON_SPACING, posY, 0, 0);
                        break;
                  }
                  if(ship.powerupCount > 1) drawString(ship.powerupCount, TRACK_ITEM_WIDTH + (ICON_SPACING << 1), posY + ((TRACK_ITEM_WIDTH - fontHeight) >> 1), LEFT_TO_RIGHT);
               }

               if(ship.killerActive && images[ITEM_KILLER] != null)
               {
                  drawFrame(FRAMES[F_ICON_KILLER], screenWidth >> 1, ICON_SPACING, 0, 0);
               }
               
               switch(gameSubState){
                  case GSS_GAME_PAUSE:
                  case GSS_GAME_OPTIONS:
                  case GSS_GAME_SOUND:
                  case GSS_GAME_FINISHED:
                        //#if !(GX20 || T610)
                        drawRaster();
                        //#endif
                        menu.drawMenu();
                     break;
               }

               if(noteVisible)
               {
                  textDraw(TEXT_BG_CLEAR);
               }

            break;

/** DRAW GS_SHOW_TOTAL_SCORES && GS_SHOW_LEVEL_SCORES *********************************************/
         case GS_SHOW_LEVEL_SCORES:
         case GS_SHOW_TOTAL_SCORES:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);

               drawFrame(FRAMES[F_GAME_TITLE], screenWidth >> 1, 0, 0, 0);

               y = (int)((FRAMES[F_GAME_TITLE] >> 32) & 0xFF);
               tIntRes = fontHeight + 7;
               
               if(levelResult == LR_QUALIFIED)
               {
                  i = UI_RESULT_BG_0;
                  j = UI_RESULT_1_0;
                  l = UI_RESULT_2_0;
               }
               else
               {
                  i = UI_RESULT_BG_1;
                  j = UI_RESULT_1_1;
                  l = UI_RESULT_2_1;
               }

               fillBG(i, 0, y, screenWidth, tIntRes);
               fillBG(j, 0, y + 1, screenWidth, 2);
               fillBG(j, 0, y + tIntRes - 1, screenWidth, 1);
               fillBG(l, 0, y + 3, screenWidth, 4);
               fillBG(l, 0, y + tIntRes - 2, screenWidth, 1);
               
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        drawString(strings[STR_LEVEL_STATISTICS], (screenWidth - strWidth[STR_TOTAL_STATISTICS]) >> 1, y + ((tIntRes - fontHeight) >> 1) + 2);
                     break;
                  case GS_SHOW_TOTAL_SCORES:
                        drawString(strings[STR_TOTAL_STATISTICS], (screenWidth - strWidth[STR_TOTAL_STATISTICS]) >> 1, y + ((tIntRes - fontHeight) >> 1) + 2);
                     break;
               }

               y += tIntRes;
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        tIntRes = (screenHeight - y) / 4;
                     break;
                  case GS_SHOW_TOTAL_SCORES:
                        tIntRes = (screenHeight - y) / 3;
                     break;
               }

               fillBG(UI_LineColor0, 0, y, screenWidth, tIntRes);
               drawString(strings[STR_TIME], TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        drawTime(levelTime, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
                  case GS_SHOW_TOTAL_SCORES:
                        drawTime(levelTotalTime, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
               }

               y += tIntRes;
               fillBG(UI_LineColor1, 0, y, screenWidth, tIntRes);
               drawString(strings[STR_SCORE], TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        drawString(levelScores, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
                  case GS_SHOW_TOTAL_SCORES:
                        drawString(levelTotalScores, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
               }
               
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        y += tIntRes;
                        fillBG(UI_LineColor0, 0, y, screenWidth, tIntRes);
                        drawString(strings[STR_BONUS], TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                        drawString(levelBonus, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
               }

               y += tIntRes;
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        tInt = UI_LineColor1;
                     break;
                  case GS_SHOW_TOTAL_SCORES:
                        tInt = UI_LineColor0;
                     break;
               }
               fillBG(tInt, 0, y, screenWidth, tIntRes);
               drawString(strings[STR_RESULT], TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
               switch(gameState){
                  case GS_SHOW_LEVEL_SCORES:
                        drawString(levelResultScores, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
                  case GS_SHOW_TOTAL_SCORES:
                        drawString(levelTotalResultScores, screenWidth - TEXT_OFFSET, y + ((tIntRes - fontHeight) >> 1), RIGHT_TO_LEFT);
                     break;
               }

            break;

/** DRAW GS_GAME_FINISHED *************************************************************************/
         case GS_GAME_FINISHED:
         case GS_ABOUT:
         case GS_TOTAL_SCORES:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);
               //#if S40v1
                  drawFrameset(FS_SPLASH, screenWidth >> 1, screenHeight >> 1);
               //#elif GX20 || S40v3big || S60v3 || S700 || E1000 || E71 || MM5600 || A900 || N6265
                  if(images[IMG_SPLASH] != null) 
                  {
                     g.drawImage(images[IMG_SPLASH], (screenWidth - images[IMG_SPLASH].getWidth()) >> 1, (screenHeight - images[IMG_SPLASH].getHeight()) >> 1, 0);
                  }
               //#else
                  drawFrame(FRAMES[F_SPLASH], screenWidth >> 1, screenHeight >> 1, 0, 0);
               //#endif
               //#if !(GX20 || T610)
               drawRaster();
               //#endif
               if(gameState == GS_TOTAL_SCORES) drawString(strings[STR_TITLE_TOP10], (screenWidth - strWidth[STR_TITLE_TOP10]) >> 1, TEXT_OFFSET);;
               textDraw(TEXT_BORDER);
            break;

/** DRAW GS_SET_SCREEN ****************************************************************************/
         case GS_SET_SCREEN:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);
               
               if(progress >= 0)
               {
                  tInt = screenWidth - 8;
                  tLong = fpMul(fpToFP(tInt), progress);
                  x = 3;
                  y = ((screenHeight - fontHeight) >> 1);
                  if(textStrIndex > -1) y += fontHeight;
                  
                  fillBG(UI_MenuBGColor, x + 1, y + 1, fpToInt(tLong), fontHeight);
                  g.setClip(0, 0, screenWidth, screenHeight);
                  g.setColor(0xffffff);
                  g.drawRect(x, y, tInt, fontHeight + 2);
               }
                  
               textDraw(TEXT_BG_CLEAR);

            break;

/** DRAW GS_EDITOR ********************************************************************************/
         case GS_EDITOR:
               fillBG(UI_BGColor, 0, 0, screenWidth, screenHeight);

               x = (screenWidth - (editorCountChars * EDITOR_CELL_WIDTH)) >> 1;
               if(x < 0) x = 0;
               y = posY - fontHeight - 1;
               
               for(i = 0; i < editorCountChars; i++)
               {
                  tInt = strGetCharIndex(editorStr[i]);
                  if(tInt == 0) tInt = DOT_CODE;

                  if(i == editorCurrentChar)
                  {
                     fillBG(0xe7e7e7, x - 2, y - 2, WChar[tInt] + 4, fontHeight + 4);
                  }
                  drawChar(tInt, x, y);
                  x += EDITOR_CELL_WIDTH;
                  if(x > screenWidth)
                  {
                     x = 0;
                     y += fontHeight + 4;
                  }
               }

               y += fontHeight + 4;
               for(i = 0; i < editorChars[0].length; i++)
                  for(j = 0; j < editorChars.length; j++)
                  {
                     tInt = strGetCharIndex(editorChars[j][i]);
                     drawChar(tInt, 
                              posX + i * EDITOR_CELL_WIDTH + ((EDITOR_CELL_WIDTH - WChar[tInt]) >> 1) + 1, 
                              y + j * EDITOR_CELL_HEIGHT + 1);
                  }
               gd.setClip(0, 0, screenWidth, screenHeight);
               gd.setColor(0xe7e7e7);
               gd.drawRect(posX + editorCurCol * EDITOR_CELL_WIDTH, y + editorCurRow * EDITOR_CELL_HEIGHT, EDITOR_CELL_WIDTH, EDITOR_CELL_HEIGHT);
               
               if((editorCurCol == editorChars[editorChars.length - 1].length - 1) && (editorCurRow == editorChars.length - 1))
               {
                  drawString(strings[STR_EDITOR_SAVE], (screenWidth - strWidth[STR_EDITOR_SAVE]) >> 1, y + editorChars.length * (EDITOR_CELL_HEIGHT + 1));
               }
               else if((editorCurCol == editorChars[editorChars.length - 1].length - 2) && (editorCurRow == editorChars.length - 1))
                    {
                       drawString(strings[STR_EDITOR_CLEAR], (screenWidth - strWidth[STR_EDITOR_SAVE]) >> 1, y + editorChars.length * (EDITOR_CELL_HEIGHT + 1));
                    }
               
            break;

/**************************************************************************************************/
      }

      isPainting = false;
   }

////////////////////////////////////////////////////////////////////////////////

   // Called when a key is pressed.
   protected void keyPressed(int keyCode)
   {
      cheatCode = (cheatCode << 8) | (keyCode & 0xff);
      
      keyIsPressed = true;
      this.keyCode = keyCode;

      updateGameObjects();
   }

////////////////////////////////////////////////////////////////////////////////

   // Called when a key is repeated (held down).
   protected void keyRepeated(int keyCode) {
   }

////////////////////////////////////////////////////////////////////////////////

   protected void keyReleased(int keyCode)
   {
      keyIsReleased = true;
      this.keyCode = keyCode;

      updateGameObjects();
   }

////////////////////////////////////////////////////////////////////////////////

   private void doRepaint()
   {
      repaint();
      serviceRepaints();
   }

////////////////////////////////////////////////////////////////////////////////

   public void paint(Graphics g)
   {
      drawObjects(g); 
   }


////////////////////////////////////////////////////////////////////////////////

   // delay - time in the msec
   private void wait(int delay)
   {
      try{ curThread.sleep(delay); } catch(Exception iex){}
   }

////////////////////////////////////////////////////////////////////////////////

   public void run() 
   {
      curThread = Thread.currentThread();
      if(curThread != null)
      {
         while((curThread == thread) && (gameState != GS_EXIT))
         {
            wait(1);
            curThread.yield();

            timer.update();

            updateObjects();
            moveObjects();

            doRepaint();
         }
      }
      midlet.exitRequested();
   }

////////////////////////////////////////////////////////////////////////////////
   public synchronized void start() 
   {
      if(thread == null)
      {
         thread = new Thread(this);
         thread.start();
      }
   }

////////////////////////////////////////////////////////////////////////////////
   public synchronized void stop() 
   {
      thread = null;
      gameState = GS_EXIT;
   }


/******************************************************************************/
/******************************************************************************/

   private void initSelectShipScreen()
   {
      int i, tInt = menu.itemHeight * 4 + 12;
      
      shipBodyState = (byte)(SHIP_ANIMATIONS[PLAYER_SHIPS[shipCurrent]].length >> 1);

      flag = false;
      textInit(PLAYER_SHIPS_DESCRIPTION[shipCurrent], TEXT_OFFSET, TEXT_OFFSET, screenWidth - (TEXT_OFFSET << 1), screenHeight - (TEXT_OFFSET << 1), TEXT_LEFT);

      ssCurrentShip = shipCurrent;
      ssCurrentShipPosX = screenWidth >> 1;
      ssCurrentShipWidth = getShipWidth(ssCurrentShip, 1);
      ssCurrentShipAnim.startAnimation(SHIP_ANIMATIONS[PLAYER_SHIPS[shipCurrent]][shipBodyState], ANIMATION_PLAY_REPEAT);
      currentRealTime = System.currentTimeMillis();
      ssStep = 0;

      ssShipAreaX1 = screenWidth >> 2;
      ssShipAreaY1 = SELECTSHIP_SHIP_OFFSET;
      ssShipAreaX2 = screenWidth - (screenWidth >> 2);
      ssShipAreaY2 = SELECTSHIP_SHIP_AREA_HEIGHT;
               
      gameState = GS_SELECTSHIP;
      gameSubState = menu.initMenu(GSS_MENU_SELECTSHIP, 0, SELECTSHIP_SHIP_AREA_HEIGHT + (((screenHeight - SELECTSHIP_SHIP_AREA_HEIGHT) - tInt) >> 1), screenWidth, tInt, false, 1);
   }

/******************************************************************************/

   private void initIntro()
   {
      int i, count;

      imgRequest(IMG_SPLASH);
      imgRequest(IMG_ALPHABET);
      imgRequest(IMG_RASTER);
      imgRequest(IMG_ARROWS);
      for(i = 0; i < PLAYER_SHIPS.length; i++) 
      {
         imgRequest(SHIP_IMAGES[PLAYER_SHIPS[i]]);
      }
      imgRequest(IMG_ENGINEFIRE);

      loadImages();

      jarLevelData = new LevelData[COUNT_LEVELS_IN_JAR][];
      for(i = 0; i < COUNT_LEVELS_IN_JAR; i++)
      {
         try
         {
            openDataInputStream((i + 1) + "_inf.bin");
            count = dinRead();
            jarLevelData[i] = new LevelData[count];
            loadLevelData(jarLevelData[i]);
         }
         catch(Exception ex)
         { 
            ex.printStackTrace(); 
         }
         inClose();
      }

      ssCurrentShipAnim = new Animation();
      ssOldShipAnim = new Animation();

      updateMutablePartOfIntro();
   }

/******************************************************************************/

   private void updateMutablePartOfIntro()
   {
      int i;
      int count;
      byte[] buff; 
      String str;

      rmsLevelData = null;
      groups = null;
      strClear();
      text = null;
      textRowWidth = null;
      menu.destroyMenu();
      System.gc();

      try
      {
         // Load group informatio
         if(!openDataInputStream(rmsRead(RMS_GROUP_INF)))
         {
            // RMS is empty
            buff = readBin(binSpecs[BIN_GROUP_INF]);
            rmsWrite(buff, RMS_GROUP_INF);
            openDataInputStream(buff);
            buff = null;
            System.gc();
         }

         strClear(groupHash);
         str = readUTF();
         if(str != null && str.length() > 0) groupHash.append(str);

         groupTotalCount = dinRead();
         groups = new GroupData[groupTotalCount];
         for(i = 0; i < groupTotalCount; i++)
         {
            str = readUTF();
            count = dinRead();
            groups[i] = new GroupData(str, (byte)count);
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }
      inClose();

      // load exist levels from jar file
      // load DLed levels from RMS
      try
      {
         if(openDataInputStream(rmsRead(RMS_LEVELS_INF)))
         {
            count = dinRead();
            rmsLevelData = new LevelData[count];
            loadLevelData(rmsLevelData);
         }
      }
      catch(Exception ex)
      { 
         System.out.println(ex.getMessage()); 
      }
      inClose();

      strRequest(STR_GROUPS_TITLE);
      strRequest(STR_BACK);
      strRequest(STR_TITLE_HISCORES);
      strRequest(STR_TITLE_TOP10);
      strRequest(STR_TITLE_NORECORDS);
      strRequest(STR_EDITOR_SAVE);
      strRequest(STR_EDITOR_CLEAR);
      strRequest(STR_TIME);
      strRequest(STR_SCORE);
      strRequest(STR_BONUS);
      strRequest(STR_RESULT);
      strRequest(STR_LEVEL_STATISTICS);
      strRequest(STR_TOTAL_STATISTICS);
      strRequest(STR_ERROR);
      //#if !FULL_CANVAS
      strRequest(STR_SELECT);
      //#endif
      for(i = 0; i < INTRO_MENUS.length; i++)
      {
         strRequest(MENU_STR[INTRO_MENUS[i]]);
      }
      for(i = 0; i < INTRO_STR.length; i++)
      {
         strRequest(INTRO_STR[i]);
      }
      for(i = 0; i < KEY_NAMES.length; i++)
      {
         strRequest(KEY_NAMES[i]);
      }
      strLoad();

      //#if SOUND_NOKIA_RT
         soundLoad(SOUND_BGMUSIC, DATA_SOUND_BGMUSIC);
         soundLoad(SOUND_END_GAME, DATA_SOUND_END_GAME);
         soundState = SS_STOPED;
         soundId = -1;
      //#elif SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
         soundLoad(SOUND_BGMUSIC);
         soundLoad(SOUND_END_GAME);
         soundId = -1;
      //#endif

      textInit(INTRO_STR);

      menu.creatMenu(INTRO_MENUS);
   }

/******************************************************************************/

   private void destroyIntro()
   {
      ssCurrentShipAnim = null;
      ssOldShipAnim = null;

      jarLevelData = null;
      rmsLevelData = null;
      groups = null;

      strClear();
      text = null;
      textRowWidth = null;
      menu.destroyMenu();

      imgClear();

      //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
         soundUnload();
      //#endif

      //#if !FULL_CANVAS
         removeAllCmds();
      //#endif

      System.gc();
   }

/**************************************************************************************************/
   
   //#if Nokia && (S30 || S40v1 || S45v1 || S45v2)
   private Image getTileImage(int imgIndex)
   {
      int imgRealIndex, manipulation;
      Image img = null;
      if(imgIndex < IMG_SOURCE.length)
      {
         imgRealIndex = (IMG_SOURCE[imgIndex] >> 16) & 0x0000FFFF;
         manipulation = IMG_SOURCE[imgIndex] & 0x0000FFFF;
         
         img = DirectUtils.createImage(TILE_WIDTH, TILE_HEIGHT, 0x00000000);
         
         if(imgRealIndex < images.length && images[imgRealIndex] != null) DirectUtils.getDirectGraphics(img.getGraphics()).drawImage(images[imgRealIndex], 0, 0, 0, manipulation);
      }
      return img;
   }
   //#endif

/**************************************************************************************************/
   
   private void loadLevel(LevelData levelData)
   {
      int i, j, index;
      long FP_100P = fpToFP(9);

      setScreen(STR_LOADING, true, -1);
      wait(500);

      groupsCount = (byte)groups.length;
      levelsCount = groups[groupCurrent].levelsCount;


      destroyIntro();
      setScreen(-1, false, fpDiv(fpToFP(1), FP_100P));

      loadCosSin(BIN_COS);
      loadCosSin(BIN_SIN);
      setScreen(-1, false, fpDiv(fpToFP(2), FP_100P));

      for(i = 0; i < GAME_MENUS.length; i++)
      {
         strRequest(MENU_STR[GAME_MENUS[i]]);
      }
      for(i = 0; i < GAME_STR.length; i++)
      {
         strRequest(GAME_STR[i]);
      }
      strRequest(STR_LOADING);
      strRequest(STR_NEXT_TRACK);
      strRequest(STR_END_RACE);
      //#if !FULL_CANVAS
         strRequest(STR_SELECT);
         strRequest(STR_PAUSE);
      //#endif
      strLoad();
      setScreen(-1, false, fpDiv(fpToFP(3), FP_100P));

      loadBinSpecifications();
      loadTrack(levelData.binTrack);
      loadBorders(levelData.binEdge);
      loadWayPoints(levelData.binWP);
      loadTrackItems(levelData.binItem);
      levelBonusTime = levelData.qTime;
      setScreen(-1, false, fpDiv(fpToFP(4), FP_100P));

      ship = new Ship(SHIP_PLAYER, PLAYER_SHIPS[shipCurrent], (track[0].tiles.length * TILE_WIDTH) >> 1, SL_COUNTTILES * TILE_HEIGHT);

      if(wayPoints != null)
      {
         npcShips = new NPC[wayPoints.length];
         for(i = 0; i < wayPoints.length; i++)
         {
            //#if S40v1
               // Limit ship count
               index = 1 - shipCurrent;
               if(0 <= index && index < PLAYER_SHIPS.length) npcType[i] = PLAYER_SHIPS[index];
            //#endif
            npcShips[i] = new NPC(npcType[i], i);
         }
      }
      setScreen(-1, false, fpDiv(fpToFP(5), FP_100P));

      imgRequest(IMG_ALPHABET);
      imgRequest(IMG_RASTER);
      imgRequest(SHIP_IMAGES[PLAYER_SHIPS[shipCurrent]]);
      for(i = 0; i < npcShips.length; i++) 
      {
         imgRequest(SHIP_IMAGES[npcShips[i].type]);
      }
      imgRequest(IMG_ENGINEFIRE);
      
      //#if !(S40v1 || T610 || S45v1 || S45v2 || X450v2 || X450v1 || E600)
      imgRequest(IMG_JUMPENGINEFIRE);
      //#endif
      
      //#if !(S40v1 || T610 || X450v2 || X450v1 || E600)
      imgRequest(IMG_SHADOW);
      //#endif
      
      //#if S40v1
      imgRequest(IMG_EXPLOSION);
      //#else
      imgRequest(IMG_EXPLOSION_BIG);
      imgRequest(IMG_EXPLOSION_SMALL);
      //#endif

      imgRequest(IMG_ROCKET);
      imgRequest(IMG_BOMB);
      imgRequest(IMG_MINE);
      imgRequest(IMG_SHIELD);
      imgRequest(IMG_HEALTH_METER);
      //#if Nokia && (S30 || S40v1 || S45v1 || S45v2)
         int realIndex;
         for(i = 0; i < trackCountElements; i++)
         {
            for(j = 0; j < track[i].tiles.length; j++)
            {
               index = track[i].tiles[j];
               if(index > -1 && index < images.length) 
               {
                  realIndex = (IMG_SOURCE[index] >> 16) & 0x0000FFFF;
                  if(imgQueue[realIndex] != 0)
                  {
                     imgRequest(realIndex);
                  }
               }
            }
         }
      //#endif

      //#if Galaxy
         imgRequest(IMG_STARS);
         //imgRequest(IMG_GALAXY);
      //#endif
      loadImages();
      setScreen(-1, false, fpDiv(fpToFP(6), FP_100P));

     //Creat laser image
      imgLaser = Image.createImage(4, screenHeight);
      Graphics gfxLaser = imgLaser.getGraphics();
      gfxLaser.setColor(0xffadff);
      gfxLaser.drawLine(0, 0, 0, screenHeight);
      gfxLaser.drawLine(3, 0, 3, screenHeight);
      gfxLaser.setColor(0xffffff);
      gfxLaser.fillRect(1, 0, 2, screenHeight);
      gfxLaser = null;

      imgSensor = Image.createImage(screenWidth, 4);
      Graphics gfxSensor = imgSensor.getGraphics();
      gfxSensor.setColor(0xffadff);
      gfxSensor.drawLine(0, 0, screenWidth, 0);
      gfxSensor.drawLine(0, 3, screenWidth, 3);
      gfxSensor.setColor(0xffffff);
      gfxSensor.fillRect(0, 1, screenWidth, 2);
      gfxSensor = null;
      System.gc(); 

      //#if Nokia && (S30 || S40v1 || S45v1 || S45v2)
         for(i = 0; i < trackCountElements; i++)
         {
            for(j = 0; j < track[i].tiles.length; j++)
            {
               index = track[i].tiles[j];
               if(index > -1 && index < images.length && images[index] == null) 
               {
                  images[index] = getTileImage(index);
               }
            }
         }
      //#endif
      setScreen(-1, false, fpDiv(fpToFP(7), FP_100P));

      //#if Galaxy
         rndOpen();

         stars = new int[STARS_COUNT];
         for(i = 0; i < STARS_COUNT; i++)
         {
            j = (rndNextInt() & 0x07FFFFFFF) % STARS.length;
            posX = ((rndNextInt() & 0x07FFFFFFF) % screenWidth) + (STARS_TILE_WIDTH >> 1);
            posY = ((rndNextInt() & 0x07FFFFFFF) % screenHeight) + (STARS_TILE_HEIGHT >> 1);
            stars[i] = ((STARS[j] << 24) & 0xFF000000) | ((posX << 12) & 0x00FFF000) | (posY & 0x00000FFF);
         }
         
         starsStepX = starsStepY = 0;
         starsOffSetX = starsOffSetY = 0;
         
         rndClose();
      //#endif

      //#if SOUND_NOKIA_RT
         soundLoad(SOUND_GO, DATA_SOUND_GO);
         soundLoad(SOUND_LASER, DATA_SOUND_LASER);
         soundLoad(SOUND_ROCKET, DATA_SOUND_ROCKET);
         soundLoad(SOUND_MINE, DATA_SOUND_MINE);
         soundLoad(SOUND_BIG_EXPLOSION, DATA_SOUND_BIG_EXPLOSION);
         soundLoad(SOUND_SMALL_EXPLOSION, DATA_SOUND_SMALL_EXPLOSION);
         soundLoad(SOUND_FIRST_PLACE, DATA_SOUND_FIRST_PLACE);
         soundLoad(SOUND_GAME_OVER, DATA_SOUND_GAME_OVER);
         soundLoad(SOUND_BONUS_GEM, DATA_SOUND_BONUS_GEM);
         soundState = SS_STOPED;
         soundId = -1;
      //#elif SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
         soundLoad(SOUND_GO);
         soundLoad(SOUND_LASER);
         soundLoad(SOUND_ROCKET);
         soundLoad(SOUND_MINE);
         soundLoad(SOUND_BIG_EXPLOSION);
         soundLoad(SOUND_SMALL_EXPLOSION);
         soundLoad(SOUND_FIRST_PLACE);
         soundLoad(SOUND_GAME_OVER);
         soundLoad(SOUND_BONUS_GEM);
         soundId = -1;
      //#endif

      explosions = new Explosion[5];
      for(i = 0; i < explosions.length; i++) explosions[i] = new Explosion();

      shots = new Shot[6];
      for(i = 0; i < shots.length; i++) shots[i] = new Shot();

      textInit(GAME_STR);
      setScreen(-1, false, fpDiv(fpToFP(8), FP_100P));

      menu.creatMenu(GAME_MENUS);
      setScreen(-1, false, fpDiv(fpToFP(9), FP_100P));

      // Init qualify time string
      timeToBuf(levelBonusTime);
      strings[STR_BONUS_MESSAGE].delete(strings[STR_BONUS_MESSAGE].length() - 8, strings[STR_BONUS_MESSAGE].length());
      strings[STR_BONUS_MESSAGE].append(timeStr.toString());
      setScreen(-1, false, fpToFP(1));

      initLevel();

      System.gc(); 
      wait(500);
   }

/******************************************************************************/

   private void initLevel()
   {
      int i;
      //uiCurrentPowerMeterIndex = 0;

      //#if !FULL_CANVAS
         if(!getLabelCmd(cmdRight).equals(strings[STR_PAUSE])) 
         {
            removeAllCmds();
            addCmd(KEY_CANCEL, strings[STR_PAUSE]);
         }
      //#endif

      clearCheatCode();

      firstTrackItem = 0;
      if(trackItems != null)
      {
         for(i = 0; i < trackItems.length; i++)
         {  
            trackItems[i].visible = true;
         }
      }
      trackCurrentRow = 0;
      trackOffSetY = 0;
      worldPosX = (screenWidth - (track[trackCurrentRow].tiles.length * TILE_WIDTH)) >> 1;
      worldPosY = screenHeight;
      worldStepX = 0; 
      worldStepY = 0;

      lastVirtualTime = currentRealTime = currentVirtualTime = 0;
      timeSchduledTask = 0;
      timeStartLoop = System.currentTimeMillis();

      // Initilisation positions of ships
      ship.init(ship.startPosX, ship.startPosY);
      ship.racingTime = 0;
      for(i = 0; i < npcShips.length; i++) 
      {
         npcShips[i].init();
      }
      for(i = 0; i < explosions.length; i++) 
      {
         explosions[i].state = EXPLOSION_STATE_FINISHED;
         explosions[i].reserved = false;
      }
      for(i = 0; i < shots.length; i++) 
      {
         shots[i].active = false;
      }

      tfeRepetition = track[0].repetition;
      tfePosY = track[0].posY;

      levelTime = 0;
      levelScores = 0;
      levelResultScores = 0;
      
      hideNote();

      gameState = GS_GAME;
      //gameSubState = GSS_GAME_PLAY;
      gameSubState = GSS_GAME_BONUS_TIME;
      showNote(STR_BONUS_MESSAGE, 3000);

      roadState = RS_READY;

      keyIsPressed = false;
      keyIsReleased = false;

      gameMode = gameMode;
      levelResult = LR_NONE;
   }

/******************************************************************************/

   private void destroyLevel()
   {
      ship = null;
      npcShips = null;
      explosions = null;
      shots = null;
      
      track = null;
      borders = null;
      cos = null;
      sin = null;
      wayPoints = null;
      npcBehavior = null;
      npcType = null;
      trackItems = null;
      //#if Galaxy
         stars = null;
      //#endif

      strClear();
      text = null;
      textRowWidth = null;
      menu.destroyMenu();

      imgClear();
      imgLaser = null;
      imgSensor = null;

      //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
         soundUnload();
      //#endif

      //#if !FULL_CANVAS
         removeAllCmds();
      //#endif

      System.gc();
   }

/******************************************************************************/

   private void loadBinSpecifications()
   {
      int i, count;
      try
      {
         if(groupCurrent < COUNT_LEVELS_IN_JAR)
         {
            // Load specification form jar
            openInputStream((groupCurrent + 1) + "_spec.bin");
         }
         else
         {
            // Load specification form RMS
            openInputStream(rmsRead(RMS_LEVELS_SPECS));
         }
         count = read();
         for(i = 0; i < count; i++)
         {
            binSpecs[i] = readInt();
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();
   }

/******************************************************************************/

   private void loadTrack(int specification)
   {
      int i, j;
      byte tilesCount; 
      //#if Nokia && (S30 || S40v1 || S45v1 || S45v2)
      int imgRealIndex;
      //#endif

      try
      {
         openInputStream(readBin(specification));

         trackCountElements = readInt();
         track = new TElement[trackCountElements];
         
         worldLength = 0;
         //System.out.println("   Count: " + count);
         for(i = 0; i < trackCountElements; i++)
         {
            track[i] = new TElement();
            track[i].repetition = (byte)read();
            track[i].offset = (byte)read();
            
            worldLength += track[i].repetition * TILE_HEIGHT;

            tilesCount = (byte)read();
            track[i].tiles = new byte[tilesCount];
            
            for(j = 0; j < tilesCount; j++)
            {
               track[i].tiles[j] = (byte)read();
               if(track[i].tiles[j] != -1)
               {
                  //#if Nokia && (S30 || S40v1 || S45v1 || S45v2)
                     if((track[i].tiles[j] >= 0) && (track[i].tiles[j] < IMG_REPLACE.length) && (IMG_REPLACE[track[i].tiles[j]] >= 0))
                     {
                        track[i].tiles[j] = IMG_REPLACE[track[i].tiles[j]];
                     }
                     imgRealIndex = (IMG_SOURCE[track[i].tiles[j]] >> 16) & 0x0000FFFF;
                     imgRequest(imgRealIndex);
                  //#elif  T610 || X450v2 || X450v1 || E600
                     if((track[i].tiles[j] >= 0) && (track[i].tiles[j] < IMG_REPLACE.length) && (IMG_REPLACE[track[i].tiles[j]] >= 0))
                     {
                        track[i].tiles[j] = IMG_REPLACE[track[i].tiles[j]];
                     }
                     imgRequest(track[i].tiles[j]);
                  //#else
                     imgRequest(track[i].tiles[j]);
                  //#endif
               }
            }

            if(i == 0)
            {
               posX = 0;
               posY = 0;
            }
            else
            {
               posX = track[i - 1].posX + (track[i].offset * TILE_WIDTH);
               posY = track[i - 1].posY + track[i - 1].repetition * TILE_HEIGHT;
            }
            track[i].posX = (short)posX;
            track[i].posY = (short)posY;
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();

      trackLength = worldLength - (FL_COUNTTILES * TILE_HEIGHT);

   }

/**************************************************************************************************/

   private void loadBorders(int specification)
   {
      int i, count, aNum, aPosX, aPosY, bNum, bPosX, bPosY, v;
      byte angle, side, type;

      try
      {
         openInputStream(readBin(specification));

         count = readInt();

         borders = new Border[count];

         for(i = 0; i < borders.length; i++)
         {
            v = readInt();
            aNum  = (v >> 24) & 0x000000FF;
            aPosX = (v >> 8) & 0x0000FFFF;
            aPosY = v & 0x000000FF;
            
            v = readInt();
            bNum  = (v >> 24) & 0x000000FF;
            bPosX = (v >> 8) & 0x0000FFFF;
            bPosY = v & 0x000000FF;

            //#if S30 || S60v1 || S60v2 || S60v3 || K700 || S700 || S40v3 || S40v3big || GX20 || P800 || P900 || S700 || V300 || E1000 || D410 || D500v1 || D500v2 || D600 || L5100 || E616 || E81 || E71 || MM7400 || A920 || MM5600 || A900 || N6265
               aPosX = convertS40(aPosX);
               aPosY = convertS40(aPosY);
               bPosX = convertS40(bPosX);
               bPosY = convertS40(bPosY);
            //#endif

            angle = (byte)read();
            side = (byte)read();
            type = (byte)read();
            borders[i] = new Border(getGWPossition(aNum, aPosX, aPosY), getGWPossition(bNum, bPosX, bPosY), angle, side, type);
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();
   }

/**************************************************************************************************/

   private void loadWayPoints(int specification)
   {
      int i, j, count, num, x, y, tInt;
      byte angle;
      
      try
      {
         openInputStream(readBin(specification));

         count = read();

         wayPoints = new WayPoint[count][];
         npcBehavior = new byte[count];
         npcType = new byte[count];
         for(i = 0; i < wayPoints.length; i++)
         {
            npcType[i] = (byte)read();
            npcBehavior[i] = (byte)read();

            count = readInt();
            wayPoints[i] = new WayPoint[count];
            for(j = 0; j < wayPoints[i].length; j++)
            {
               tInt = readInt();
               num = (tInt >> 24) & 0x000000FF;
               x = (tInt >> 8) & 0x0000FFFF;
               y = tInt & 0x000000FF;
               //#if S30 || S60v1 || S60v2 || S60v3 || K700 || S700 || S40v3 || S40v3big || GX20 || P800 || P900 || S700 || V300 || E1000 || D410 || D500v1 || D500v2 || D600 || L5100 || E616 || E81 || E71 || MM7400 || A920 || MM5600 || A900 || N6265
                  x = convertS40(x);
                  y = convertS40(y);
               //#endif
               num = getGWPossition(num, x, y);
               angle = (byte)read();;
               wayPoints[i][j] = new WayPoint((short)((num << 1) >> 17), (short)(num & 0x0000FFFF), angle);
            }
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();
   }

/**************************************************************************************************/

   private void loadTrackItems(int specification)
   {
      int i, count, v, num, x, y;
      byte type;
      try
      {
         openInputStream(readBin(specification));

         count = readInt();

         trackItems = new TrackItems[count];

         for(i = 0; i < trackItems.length; i++)
         {
            type = (byte)read();
            imgRequest(type);

            v = readInt();
            num  = (v >> 24) & 0x000000FF;
            x = (v >> 8) & 0x0000FFFF;
            y = v & 0x000000FF;
            
               //#if S30 || S60v1 || S60v2 || S60v3 || K700 || S700 || S40v3 || S40v3big || GX20 || P800 || P900 || S700 || V300 || E1000 || D410 || D500v1 || D500v2 || D600 || L5100 || E616 || E81 || E71 || MM7400 || A920 || MM5600 || A900 || N6265
                  x = convertS40(x);
                  y = convertS40(y);
               //#endif

            num = getGWPossition(num, x, y);

            trackItems[i] = new TrackItems(type, (short)((num << 1) >> 17), (short)(num & 0x0000FFFF));
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();
   }

/**************************************************************************************************/

   private int getGWPossition(int num, int x, int y)
   {
      int i, num_begin, num_end;

      num_end = 0;
      for(i = 0; i < trackCountElements; i++)
      {
         num_begin = num_end;
         num_end += track[i].repetition;
         if((num >= num_begin) && (num < num_end))
         {
            x += track[i].posX;
            y += track[i].posY + ((num - num_begin) * TILE_HEIGHT);
               break;
         }
      }
      return ((x << 16) & 0xFFFF0000) | (y & 0x0000FFFF);
   }

/******************************************************************************/

   private void loadCosSin(int index)
   {
      int i, count;
      long value;

      try
      {
         openInputStream(readBin(binSpecs[index]));

         count = SHIP_MAX_ANGLE + 1;

         switch(index){
            case BIN_COS:
                  cos = new long[count];
               break;
            case BIN_SIN:
                  sin = new long[count];
               break;
         }

         for(i = 0; i < count; i++)
         {
            value = fpDiv(fpToFP(readInt()), fpToFP(10000));
            switch(index){
               case BIN_COS:
                     cos[i] = value;
                  break;
               case BIN_SIN:
                     sin[i] = value;
                  break;
            }
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();
   }

/******************************************************************************/

   private byte[] readBin(int spec)
   {
      int binIndex;
      int binSize;
      int size;
      int ptr;
      int entryNum;
      boolean found;

      byte[] b = null;
      
      try
      {
         found = false;
         binIndex = (spec >> 8) & 0xFF;
         binSize = (spec >> 16) & 0xFFFF;
         if(binIndex <= COUNT_LEVELS_IN_JAR)
         {
            // Load bin form jar
            openInputStream(Integer.toString(binIndex) + ".bin");
         }
         else
         {
            // Load bin form RMS
            openInputStream(rmsRead(RMS_LEVELS_BIN));
         }
         
         readInt();

         for(ptr = 0; !found; ptr++)
         {
            // reading next bin entry size
            size = readInt();
            if(size == -1)
            {
               // EOF
               break;
            }

            // searching for request matching found entry
            entryNum = spec & 0xFF;

            if((binSize == size) && (entryNum == ptr))
            {
               // entry found
               b = new byte[size];
               read(b, 0, size);
               found = true;
            }
            
            if(!found)
            {
               // skip not needed entry
               skip(size);
            }
         }
      }
      catch(Exception ex)
      { 
         ex.printStackTrace(); 
      }

      inClose();

      return b;
   }

/**************************************************************************************************/

   private void loadLevelData(LevelData[] data) throws Exception
   {
      int i;
      int a, b, c, d, t;

      for(i = 0; i < data.length; i++)
      {
         strClear(tempResStr);
         tempResStr.append(readUTF());
         a = dinReadInt();
         b = dinReadInt();
         c = dinReadInt();
         d = dinReadInt();
         t = dinReadInt();

         data[i] = new LevelData(tempResStr.toString(), a, b, c, d, t);
      }
   }


/**************************************************************************************************/

   private void hideNote()
   {
      timer.unSet();
      noteVisible = false;
   }

   private void showNote(int id, int time)
   {
      hideNote();

      noteVisible = true;
      textInit(id, 0, 0, screenWidth, screenHeight, TEXT_CENTER);

      timer.set(time);
   }

/**************************************************************************************************/

   private static void correctExplosionIndex()
   {
      while(explosionFirstFreeIndex < explosions.length && !explosions[explosionFirstFreeIndex].isFinished()) explosionFirstFreeIndex++;
   }

   public static void addExplosion(int index, byte type, int x, int y)
   {
      if(index < explosions.length) 
      {
         explosions[index].activate(type, x, y);
         correctExplosionIndex();
         //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
            //#if S40v1
               soundPlay(SOUND_BIG_EXPLOSION);
            //#else
               switch(type){
                  case A_EXPLOSION_BIG:
                        soundPlay(SOUND_BIG_EXPLOSION);
                     break;
                  default:
                        soundPlay(SOUND_SMALL_EXPLOSION);
                     break;
               }
            //#endif
         //#endif                                                       
      }
   }

/**************************************************************************************************/
   
   private static void correctShotIndex()
   {
      while(shotFirstFreeIndex < shots.length && shots[shotFirstFreeIndex].active) shotFirstFreeIndex++;
   }

   public static void addShot(Ship ship, byte type)
   {
      boolean flag;
      if(shotFirstFreeIndex < shots.length)
      {
         flag = false;
         switch(type){
            case WEAPON_LASER:
                  flag = shots[shotFirstFreeIndex].activate(ship, type, explosionFirstFreeIndex);
                  if(flag) 
                  {
                     correctExplosionIndex();
                     //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                        soundPlay(SOUND_LASER);
                     //#endif                                                       
                  }
               break;
            case WEAPON_ROCKET:
            case WEAPON_MINE:
            case WEAPON_BOMB:
                  flag = shots[shotFirstFreeIndex].activate(ship, type, -1);
                  //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                     if(flag)
                     {
                        if(type == WEAPON_ROCKET) 
                        {
                           soundPlay(SOUND_ROCKET);                     
                        }
                        else 
                        {
                           soundPlay(SOUND_MINE);                     
                        }
                     }
                  //#endif                                                       
               break;
         }
         if(flag) correctShotIndex();
      }
   }

/**************************************************************************************************/

   public static int getAbsoluteLevelNumber(int group, int level)
   {
      int i, count = 0;
      if(groups != null)
      {
         for(i = 0; (i < group) && (i < groups.length); i++) count += groups[i].levelsCount;
      }
      return count + level;
   }

/**************************************************************************************************/
/**                                                                                              **/
/**                                         Network part                                         **/
/**                                                                                              **/
/**************************************************************************************************/

   /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

//*****************************************************************************
//#if mp
      public static void httpOpenGetConnection(String url) throws Exception
      {
         httpConn = (HttpConnection)Connector.open(url);
         httpConn.setRequestMethod(HttpConnection.GET);
         httpConn.setRequestProperty("Content-Language","en-US");
         httpConn.setRequestProperty("User-Agent","Profile/MIDP-1.0 Configuration/CLDC-1.0");

         if(httpGetResponseCode() != 200)
         {
            throw new Exception("HTTP " + httpGetResponseCode());
         }
      }

/**************************************************************************************************/

      public static int httpGetResponseCode() throws Exception
      {
         return httpConn.getResponseCode();
      }

/**************************************************************************************************/

      public static int httpGetContentLength() throws Exception
      {
         return (int)httpConn.getLength();
      }

/**************************************************************************************************/

      public static void httpOpenInputStream() throws Exception
      {
         in = httpConn.openInputStream();
      }

/**************************************************************************************************/

      public static void httpClose()
      {
         try
         {
            if(in != null) 
            {
               in.close();
            }
         }
         catch(Exception ex){}

         try
         {
            if(httpConn != null) 
            {
               httpConn.close();
            }
         }
         catch(Exception ex){}

         in = null;
         httpConn = null;
         System.gc();
      }

/**************************************************************************************************/

      static void httpOpenPostConnection(String url) throws Exception
      {
         httpConn = (HttpConnection)Connector.open(url, Connector.READ_WRITE, false);

         httpConn.setRequestMethod(HttpConnection.POST);
         httpConn.setRequestProperty("Content-Language", "en-US");
         httpConn.setRequestProperty("User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0");
      }

/**************************************************************************************************/

      static void httpPostString(String name, String value, int networkState) throws Exception
      {
         if(name != null)
         {
            if(networkState == 1)
            {
//               System.out.println(name + " = " + value);
               out.write(name.getBytes());
               out.writeByte('=');
               out.writeInt(value.length());
               out.write(value.getBytes());
            }
            else
            {
               httpContentLength += name.length() + value.length() + 5;
            }
         }
      }

/**************************************************************************************************/

      static int httpSetLength(int mode, int networkState) throws Exception
      {
         httpPostString("lvl", "total", networkState);
         httpPostString("mode", Integer.toString(mode), networkState);
         httpPostString("ll", "123456", networkState);

         if (GameScreen.midlet.getAppProperty("PK") != null) {
            httpPostString("part", GameScreen.midlet.getAppProperty("PK"), networkState);
         }
         else {
            httpPostString("part", "NA", networkState);
         }

         httpPostString("u", "dummy", networkState);
         httpPostString("p", "changeme", networkState);
         httpPostString("evt", "Space Racer", networkState);

         httpPostString("cid", Integer.toString(0), networkState);
         httpPostString("v", GameScreen.midlet.getAppProperty("MIDlet-Version"), networkState);

         if(networkState == 0)
         {
            httpConn.setRequestProperty("Content-Length", Integer.toString(httpContentLength));
            out = new DataOutputStream(httpConn.openOutputStream());
         }
         return httpContentLength;
      }

/**************************************************************************************************/

      public byte[] downloadFile(String url)
      {
         int i, j, contentLength;
         byte[] buff = null;
    
         setScreen(STR_CONNECTING, false, -1);
         try
         {
            httpOpenGetConnection(url);
            httpOpenInputStream();

            contentLength = httpGetContentLength();

            setScreen(STR_LOADING, false, -1);
            buff = new byte[contentLength > 0 ? contentLength : 40000];
            for(i = 0; ((j = in.read()) != -1) && (i < buff.length); i++)
            {
               if(i % 100 == 0)
               {
                  //setScreen("downloading", div(i << FP, (buff.length - 1) << FP), true);
               }
               buff[i] = (byte)j;
            }
         }
         catch(Exception ex2)
         {
             buff = null;
             System.gc();
         }
         httpClose();
         
         return buff;
      }

/**************************************************************************************************/

      private int post(int mode) throws Exception
      {
         char c;
         int state = STATE_KEY, r, i, j = 0, fieldLength = 0, bytesCount = 0;
         StringBuffer key = new StringBuffer();
         StringBuffer value = new StringBuffer();

         outClose();

         httpOpenInputStream();
         connectionState = CS_CONNECTED;

         int httpResponseCode = httpGetResponseCode();

         // check http response code
         if(httpResponseCode != HTTP_OK)
         {
            throw new Exception(strings[STR_ERROR].toString() + httpResponseCode);
         }

         httpContentLength = httpGetContentLength();

         byte[] httpResponse = new byte[3];
         for(i = 0; i < httpResponse.length; i++) httpResponse[i] = (byte)read();

         try
         {
            httpResponseCode = Integer.parseInt(new String(httpResponse));
         }
         catch(Exception nfEx)
         {
            throw new Exception(strings[STR_ERROR].toString());
         }

         // parsing request data stream
         for (i = 3; ; i++)
         {           
            if(httpContentLength > 0)
            {
               if (i >= httpContentLength) break;
            }

            r = read();
            if (r == -1) break;

            c = (char)r;

            switch(state)
            {
               case STATE_KEY:
                     if(c == '=')
                     {
                        bytesCount = 0;
                        fieldLength = 0;
                        value.setLength(0);
                        state = STATE_LENGTH;
                     }
                     else key.append(c);
                  break;

               case STATE_LENGTH:
                     fieldLength = (fieldLength << 8) | r;
                     if(++ bytesCount >= 4)
                     {
                        state = STATE_VALUE;
                        bytesCount = 0;
                     }     
                  break;

               case STATE_VALUE:
                     if(bytesCount < fieldLength)
                     {
                        value.append(c);
                     }  
                     if(++ bytesCount >= fieldLength)
                     {
                        // got response data
                        // fill variables
                        switch(mode)
                        { 
                           case MODE_UL_TOTAL_SCORES:
                                 if(key.toString().equals("place"))
                                 {
                                    // Get place which player took
                                    //System.out.println("Place: " + (Integer.parseInt(value.toString()) + 1));
                                    try
                                    {
                                       place = Integer.parseInt(value.toString()) + 1;
                                    }
                                    catch(Exception ex){}
                                 }
                                 if(key.toString().equals("id"))
                                 {
                                    strClear(user[USER_ID]);
                                    user[USER_ID].append(value.toString());
                                    userWrite();
                                 }
                              break;
                           case MODE_DL_TOTAL_SCORES:
                                 if(key.length() > 6) key.delete(6, key.length());
                                 if(strings[STR_SCORES].length() > 0) strings[STR_SCORES].append('|');
                                 strings[STR_SCORES].append(Integer.toString(j + 1) + '.' + key.toString() + '^' + Integer.parseInt(value.toString()));
                              break;
                        }
                  
                        state = STATE_KEY;
                        key.setLength(0);                   
                        j++;
                     }
                  break;
            }
         }
         // check digiment error code
         if(httpResponseCode != HTTP_OK)
         {
            throw new Exception(strings[STR_ERROR] + key.toString());
         }

         return httpContentLength;
      }

/**************************************************************************************************/

      private int doPost(int functionIndex, int totalScores, long time, int scores)
      {
         //#if mp
         int networkState;
         try
         {
            setScreen(STR_CONNECTING, false, -1);

            place = -1;

            connectionState = CS_NOT_CONNECTED;

            httpContentLength = 0;

            httpOpenPostConnection(midlet.getAppProperty("GServer-URL"));

            setScreen(STR_CONNECTING, false, -1);

            for(networkState = 0; networkState < 2; networkState++)
            {
               switch (functionIndex){
                  case MODE_UL_TOTAL_SCORES: // upload top 10
                        if(user[USER_ID].length() > 1) 
                        {
                           httpPostString("id", user[USER_ID].toString(), networkState);
                        }
                        httpPostString("ctrl", "0", networkState);
                        if((user != null) && (user[USER_NAME] != null)) httpPostString("n", user[USER_NAME].toString(), networkState);

                        System.out.println("Post name " + user[USER_NAME].toString());
                        System.out.println("Post id " + user[USER_ID].toString());
                        System.out.println("Post session" + gameSession.toString());

                        httpPostString("session", gameSession.toString(), networkState);
                        httpPostString("s0", Integer.toString(totalScores), networkState);
                        httpPostString("s1", Long.toString(time), networkState);
                        httpPostString("s2", Long.toString(scores), networkState);

                        if(midlet.getAppProperty("Target-Dev") != null)
                        {
                           httpPostString("hw", midlet.getAppProperty("Target-Dev"), networkState);
                        }
                        else
                        {
                           httpPostString("hw", "NA", networkState);
                        }
                     break;

                  case MODE_DL_TOTAL_SCORES: // load top 10
                        strClear(strings[STR_SCORES]);
                        httpPostString("count", Integer.toString(HISCORES_COUNT), networkState);
                     break;

               }
               httpSetLength(functionIndex, networkState);
            }
            post(functionIndex);
            
            connectionState = CS_SUCCESSFUL;

            if(functionIndex == MODE_DL_TOTAL_SCORES)
            {
               if(strings[STR_SCORES].length() == 0)
               {
                  strings[STR_SCORES].append(strings[STR_TITLE_NORECORDS].toString());
               }
            }
         }
         catch(Exception ex)
         {
            connectionState = CS_ERROR;
         }

         outClose();
         httpClose(); 
         //#else
//-------------------- If singlplayer mode--------------------------------------------------------
         int i;

         place = -1;
         switch (functionIndex)
         {
          case MODE_UL_TOTAL_SCORES: // upload top 10
               setScreen(STR_EDITOR_SAVE, false, -1);
               place = top10AddNewScore(user[USER_NAME].toString(),totalScores);
               break;
          case MODE_DL_TOTAL_SCORES: // load top 10
               setScreen(STR_LOADING, false, -1);

               strClear(strings[STR_SCORES]);
               
               for(i = 0; i < top10count; i++)
               {
                if(strings[STR_SCORES].length() > 0) strings[STR_SCORES].append('|');
                strings[STR_SCORES].append(Integer.toString(i + 1) + '.' + top10Name[i] + '^' + top10Score[i]);
               }

               if(strings[STR_SCORES].length() == 0)
               {
                  strings[STR_SCORES].append(strings[STR_TITLE_NORECORDS].toString());
               }

               break;
         }
         connectionState = CS_SUCCESSFUL;
         //#endif

         return connectionState;
      }

   //#endif

/**************************************************************************************************/
/**************************************************************************************************/

   //#if S30 || S60v1 || S60v2 || S60v3 || K700 || S700 || S40v3 || S40v3big || GX20 || P800 || P900 || S700 || V300 || E1000 || D410 || D500v1 || D500v2 || D600 || L5100 || E616 || E81 || E71 || MM7400 || A920 || MM5600 || A900 || N6265
   private int convertS40(int v)
   {
      return fpToInt(fpMul(fpToFP(v), K_CORRECTS));
   }
   //#endif

/**************************************************************************************************/

   private int getShipWidth(int shipIndex, int state)
   {
      return ((SHAPES[SHIP_SHAPES[PLAYER_SHIPS[shipIndex]]][state] >> 24) & 0xff) + ((SHAPES[SHIP_SHAPES[PLAYER_SHIPS[shipIndex]]][state] >> 8) & 0xff);
   }

/**************************************************************************************************/

   public static void openInputStream(String resource) throws Exception
   {
      in = midlet.getClass().getResourceAsStream("/" + resource);
   }

/**************************************************************************************************/

   public static boolean openInputStream(byte[] data) throws Exception
   {
      if(data == null) return false;
      
      in = new ByteArrayInputStream(data, 0, data.length);
      return true;
   }

/**************************************************************************************************/

   public static void inClose()
   {
      if(in != null) 
      {
         try{ 
            in.close();  
         } 
         catch(Exception ex){}
         in = null;
      }
      if(din != null) 
      {
         try{ 
            din.close(); 
         } 
         catch(Exception ex){}
         din = null;
      }
      System.gc();
   }

/**************************************************************************************************/

   public static void skip(int count) throws Exception
   {
      in.skip(count);
   }

/**************************************************************************************************/

   public static int read() throws Exception
   {
      return in.read();
   }

/**************************************************************************************************/

   public static int readInt() throws Exception
   {
      int v  = (in.read() << 24) & 0xFF000000;
          v |= (in.read() << 16) & 0x00FF0000;
          v |= (in.read() << 8 ) & 0x0000FF00;
          v |=  in.read()        & 0x000000FF;
      return v;
   }

/**************************************************************************************************/

   public static int read(byte[] b, int off, int len) throws Exception
   {

      int i = 0, c;
      try 
      {
          for(; i < len ; i++) 
          {
            c = in.read();
            if (c == -1) 
            {
                break;
            }
            b[off + i] = (byte)c;
         }
      } 
      catch (Exception ee){}
      return i;
   }

/**************************************************************************************************/
/**************************************************************************************************/

   public static void openDataInputStream(String resource) throws Exception
   {
      din = new DataInputStream(midlet.getClass().getResourceAsStream("/" + resource));
   }

/**************************************************************************************************/

   public static boolean openDataInputStream(byte[] data) throws Exception
   {
      if(data == null) return false;
      else
      {
         openInputStream(data);
         if(in == null) return false;
         else
         {
            din = new DataInputStream(in);
            return true;
         }
      }
   }

/**************************************************************************************************/

   public static String readUTF() throws Exception
   {
      return din.readUTF();
   }

/**************************************************************************************************/

   public static int dinRead() throws Exception
   {
      return din.read();
   }

/**************************************************************************************************/

   public static boolean dinReadBoolean() throws Exception
   {
      return din.readBoolean();
   }

/**************************************************************************************************/

   public static int dinReadInt() throws Exception
   {
      int v  = (din.read() << 24) & 0xFF000000;
          v |= (din.read() << 16) & 0x00FF0000;
          v |= (din.read() << 8 ) & 0x0000FF00;
          v |=  din.read()        & 0x000000FF;
      return v;
   }

/**************************************************************************************************/

   public static int dinRead(byte[] b, int off, int len) throws Exception
   {

      int i = 0, c;
      try 
      {
          for(; i < len ; i++) 
          {
            c = din.read();
            if (c == -1) 
            {
                break;
            }
            b[off + i] = (byte)c;
         }
      } 
      catch (IOException ee){}
      return i;
   }

/**************************************************************************************************/
/**************************************************************************************************/

   public static void openDataOutputStream(int size) throws Exception
   {
      baos = new ByteArrayOutputStream();
      out = new DataOutputStream(baos);
   }

/**************************************************************************************************/

   public static void writeInt(int value) throws Exception
   {
      out.writeInt(value);
   }

/**************************************************************************************************/

   public static void writeUTF(String str) throws Exception
   {
      out.writeUTF(str);
   }

/**************************************************************************************************/

   public static void writeBoolean(boolean value) throws Exception
   {
      out.writeBoolean(value);
   }

/**************************************************************************************************/

   public static void write(byte[] data, int offset, int length) throws Exception
   {
      out.write(data, offset, length);
   }


/**************************************************************************************************/

   public static void baosClose()
   {
      try
      {
         if(baos != null) 
         {
            baos.close();
         }
      }
      catch(Exception ex){}
      baos = null;
      System.gc();
   }

/**************************************************************************************************/

   public static void outClose()
   {
      try
      {
         if(out != null) 
         {
            out.close();
         }
      }
      catch(Exception ex){}
      out = null;
      System.gc();
   }

/**************************************************************************************************/
/**************************************************************************************************/

   public byte[] rmsRead(String rmsName)
   {
      int count;
      byte[] data = null;

      try{
         rst = RecordStore.openRecordStore(rmsName, false);

         openDataInputStream(rst.getRecord(1));
         
         count = dinReadInt();
         data = new byte[count];
         dinRead(data, 0, count);

         inClose();
         rst.closeRecordStore();
      }
      catch(Exception ex)
      {
         ex.printStackTrace();
      }

      rst = null;
      System.gc();

      return data;
   }

/**************************************************************************************************/

   public boolean rmsWrite(byte[] data, String rmsName)
   {
      boolean flag = false;
      byte[] buff;

      if(data == null) return false;

      rmsDelete(rmsName);

      try{
         rst = RecordStore.openRecordStore(rmsName, true);;
        
         openDataOutputStream(32 + data.length);

         writeInt(data.length);
         write(data, 0, data.length);
         buff = baos.toByteArray();
         if(rst.getNumRecords() > 0) 
         {
            rst.setRecord(1, buff, 0, buff.length);
         }
         else 
         {
            rst.addRecord(buff, 0, buff.length);
         }
         buff = null;

         baosClose();
         outClose();
         rst.closeRecordStore();
         flag = true;
      }
      catch(Exception ex)
      {
         ex.printStackTrace(); 
      }

      rst = null;
      System.gc();
      
      return flag;
   }

   private void rmsDelete(String rmsName)
   {
   
      try{
         rst = RecordStore.openRecordStore(rmsName, true);
         rst.closeRecordStore();
         rst.deleteRecordStore(rmsName);
      }
      catch(Exception ex)
      {
         ex.printStackTrace();
      }
      rst = null;
      System.gc();
   }

/**************************************************************************************************/
/**************************************************************************************************/

   // Check intersection between two segments: A(ax1,ay1,ax2,ay2) and B(bx1,by1,bx2,by2)
   // Function returns: 
   //     true if segments intersect, 
   //     false - if its intersects in the end of segments or don't intersect at all
   public static boolean isIntersection(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
   {
      long v1 = (bx2 - bx1) * (ay1 - by1) - (by2 - by1) * (ax1 - bx1);
      long v2 = (bx2 - bx1) * (ay2 - by1) - (by2 - by1) * (ax2 - bx1);
      long v3 = (ax2 - ax1) * (by1 - ay1) - (ay2 - ay1) * (bx1 - ax1);
      long v4 = (ax2 - ax1) * (by2 - ay1) - (ay2 - ay1) * (bx2 - ax1);
      return ((v1 * v2) <= 0) && ((v3 * v4) <= 0);
   }

/**************************************************************************************************/

   // Function returns coordinates x, y of point of crossing two segments
   // returns:   
   //    x - (int >> 16) & 0xffff0000
   //    y - int & 0xffff0000
   public static int getCrossPoint(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
   {
      long fp_1, a, b, c, d, e, f, dt, det, t, x, y;

      fp_1 = fpToFP(1);
      a = fpToFP(x2 - x1);
      b = fpToFP(x3 - x4);
      c = fpToFP(x3 - x1);
      d = fpToFP(y2 - y1);
      e = fpToFP(y3 - y4);
      f = fpToFP(y3 - y1);

      det = fpMul(a, e) - fpMul(b, d); 
      
      if(det == 0) return 0;

      dt = fpMul(c, e) - fpMul(f, b);
      t = fpDiv(dt, det);

      x = fpMul(fpToFP(x1), (fp_1 - t)) + fpMul(fpToFP(x2), t);
      y = fpMul(fpToFP(y1), (fp_1 - t)) + fpMul(fpToFP(y2), t);
      return ((fpToInt(x) << 16) & 0xffff0000) | (fpToInt(y) & 0x0000ffff);
   }

//**************************************************************************************************

   public static void rndOpen()
   {
      rnd = new Random();
   }

   public static int rndNextInt()
   {
      if(rnd != null) return rnd.nextInt();
      else return 0;
   }

   public static void rndClose()
   {
      rnd = null;
      System.gc();
   }

//**************************************************************************************************

   public static int min(int a, int b)
   {
      if(a < b) return a;
      else return b;
   }

//**************************************************************************************************

   public static int max(int a, int b)
   {
      if(a > b) return a;
      else return b;
   }

//**************************************************************************************************

   public static int abs(int v)
   {
      if(v < 0) return -v;
      else return v;
   }
   
//**************************************************************************************************

  static public long fpToFP(long a) 
  {
    return (a << FP);
  }

  static public long fpToLong(long a)
  {
    return (a >> FP);
  }

  static public int fpToInt(long a)
  {
    return (int)(a >> FP);
  }

  static public short fpToShort(long a)
  {
    return (short)(a >> FP);
  }

  static public long fpMul(long a, long b)
  {
    return ((a * b) >> FP);
  }

  static public long fpDiv(long a, long b)
  {
    return ((a << FP) / b);
  }
/**************************************************************************************************/

   public static void clearCheatCode()
   {
      cheat_Shield   = false;
      cheat_Nitro    = false;
      cheat_Missiles = false;
      cheat_Bomb     = false;
      cheat_Mine     = false;
   }

   //#if SOUND_NOKIA_RT

      public void soundStateChanged(Sound sound, int event) 
      {
          if(event != Sound.SOUND_PLAYING && soundState != SS_PAUSED)
          {
            soundState = SS_STOPED;
            soundId = -1;
          }
      }

      public void soundLoad(byte id, byte[] data)
      {
         if(id >= 0 && id < sounds.length)
         {
            try
            {
               sounds[id] = new Sound(data, Sound.FORMAT_TONE);
               sounds[id].setSoundListener(this);
            }
            catch (Exception ex)
            {
               //ex.printStackTrace();
            }
         }
      }

      public void soundUnload()
      {
         for(int i = 0; i < sounds.length; i++) 
         {
            if(sounds[i] != null)
            {
               sounds[i].release();
               sounds[i] = null;
            }
         }
         System.gc();
      }

      public static void soundPlay(byte id)
      {
         if(settings[SETTINGS_SOUND] == 1)
         {
            if(soundState == SS_PLAYING) 
            {
               soundStop(soundId);
               //return;
            }
            soundState = SS_PLAYING;
            soundId = id;
            try{
               //System.out.println("Play " + id);
                //m_sounds[i].setGain(128);
               sounds[id].play(1);
            }
            catch(Throwable throwable)
            {
               //throwable.printStackTrace();
            }
         }
      }

      public static void soundStop(byte id)
      {
         try
         {
            //System.out.println("Stop");
            soundState = SS_STOPED;
            sounds[id].stop();
            soundId = -1;
         }
         catch(Throwable throwable) {
         }
      }

/*****************************************************************************************************************************/

   //#elif SOUND_MMAPI

      public void playerUpdate(Player player, String event, Object eventData)
      {
         if(event == PlayerListener.END_OF_MEDIA) 
         {
            //#if !(T610 || S60v2 || S60v3 || S65 || C65 || CL75 || E81)
               try{
                  soundPlayer[soundId].deallocate();
               }
               catch(Exception ex) {}
            //#endif
            soundId = -1;
         }
      }

      public static byte getPlayerState(byte id)
      {
         if(-1 < id && id < soundPlayer.length)
         {
            try{
               if(soundPlayer[id] == null) return SS_NOT_LOADED;

               switch(soundPlayer[id].getState())
               {
                  case Player.PREFETCHED:
                     return SS_PREFETCHED;

                  case Player.STARTED:
                     return SS_STARTED;

                  case Player.CLOSED:
                     return SS_CLOSED;

                  case Player.REALIZED:
                     return SS_REALIZED;

                  case Player.UNREALIZED:
                     return SS_UNREALIZED;
               }
            }
            catch (Exception ex)
            {
               ex.printStackTrace();
            }
         }
         return SS_NOT_LOADED;
      }

      public void soundLoad(byte id)
      {
         if(id >= 0 && id < soundPlayer.length)
         {
            try
            {
               switch (id){
                  case SOUND_BGMUSIC:
                        openDataInputStream("bgmusic.mid");
                     break;
                  case SOUND_GO:
                        openDataInputStream("go.mid");
                     break;
                  case SOUND_LASER:
                        openDataInputStream("laser.mid");
                     break;
                  case SOUND_ROCKET:
                        openDataInputStream("rocket.mid");
                     break;
                  case SOUND_MINE:
                        openDataInputStream("mine.mid");
                     break;
                  case SOUND_BIG_EXPLOSION:
                        openDataInputStream("b_explosion.mid");
                     break;
                  case SOUND_SMALL_EXPLOSION:
                        openDataInputStream("s_explosion.mid");
                     break;
                  case SOUND_FIRST_PLACE:
                        openDataInputStream("first_place.mid");
                     break;
                  case SOUND_GAME_OVER:
                        openDataInputStream("game_over.mid");
                     break;
                  case SOUND_BONUS_GEM:
                        openDataInputStream("bonus.mid");
                     break;
                  case SOUND_END_GAME:
                        openDataInputStream("end_game.mid");
                     break;
               }
               soundPlayer[id] = Manager.createPlayer(din, "audio/midi");
               soundPlayer[id].realize();
               //#if T610 || S60v2 || S60v3 || S65 || C65 || CL75 || E81
                  soundPlayer[id].prefetch();
               //#endif
               soundPlayer[id].addPlayerListener(this);
            }
            catch (Exception ex)
            {
               ex.printStackTrace();
            }
            finally
            {
               inClose();
            }
         }
      }

      public  void soundUnload()
      {
         for(int i = 0; i < soundPlayer.length; i++) 
         {
            if(soundPlayer[i] != null)
            {
               soundPlayer[i].close();
               soundPlayer[i] = null;
            }
         }
         System.gc();
         soundId = -1;
      }


      public static void soundPlay(byte id)
      {
         if(settings[SETTINGS_SOUND] == 1)
         {
            if(id != soundId)
            {
               soundStop(soundId);
               try{
                  //#if !(T610 || S60v2 || S60v3 || S65 || C65 || CL75 || E81)
                     soundPlayer[id].prefetch();
                  //#endif
                  soundPlayer[id].start();
                  soundId = id;
               }
               catch (Exception ex) 
               {
                  ex.printStackTrace();
               }
            }
         }
      }

      public static void soundStop(byte id)
      {
         if(getPlayerState(id) == SS_STARTED)
         {
            try{
               soundPlayer[id].stop();
               soundId = -1;
            }
            catch (Exception ex) { }
            //#if !(T610 || S60v2 || S60v3 || S65 || C65 || CL75 || E81)
               try{
                  soundPlayer[id].deallocate();
               }
               catch (Exception ex) { }
            //#endif
         }
      }

/*****************************************************************************************************************************/

   //#elif SAMSUNG_MMF

/**  SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF SAMSUNG_MMF **/
      public static void soundLoad(byte id)
      {
         if(id >= 0 && id < soundPlayer.length)
         {
            try
            {
               switch (id)
               {
                  case SOUND_BGMUSIC:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/bgmusic.mmf");
                     break;
                  case SOUND_GO:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/go.mmf");
                     break;
                  case SOUND_LASER:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/laser.mmf");
                     break;
                  case SOUND_ROCKET:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/rocket.mmf");
                     break;
                  case SOUND_MINE:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/mine.mmf");
                     break;
                  case SOUND_BIG_EXPLOSION:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/b_explosion.mmf");
                     break;
                  case SOUND_SMALL_EXPLOSION:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/s_explosion.mmf");
                     break;
                  case SOUND_FIRST_PLACE:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/first_place.mmf");
                     break;
                  case SOUND_GAME_OVER:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/game_over.mmf");
                     break;
                  case SOUND_BONUS_GEM:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/bonus.mmf");
                     break;
                  case SOUND_END_GAME:
                        soundPlayer[id] = new AudioClip(AudioClip.TYPE_MMF, "/end_game.mmf");
                     break;
               }
            }
            catch (Exception ex)
            {
               ex.printStackTrace();
            }
         }
      }

      public static void soundUnload()
      {
         for(int i = 0; i < soundPlayer.length; i++) 
         {
            if(soundPlayer[i] != null)
            {
               soundStop(i);
               soundPlayer[i] = null;
            }
         }
         System.gc();
      }

      public static void soundPlay(byte id)
      {
         if(settings[SETTINGS_SOUND] == 1 && id >= 0 && id < soundPlayer.length)
         {
            try{
               soundPlayer[id].stop(); 
            }catch(Exception e) {}
            try{
               soundPlayer[id].play(1, 5); 
            }catch(Exception e) {}
            soundId = id;
         }
      }

      public static void soundStop(int id)
      {
         if(id >= 0 && id < soundPlayer.length)
         {
            try{
               soundPlayer[id].stop(); 
            }catch(Exception e) {}
            soundId = -1;
         }
      }

/*****************************************************************************************************************************/

   //#elif SHARP_MMF

      public void soundLoad(byte id)
      {
         if(id >= 0 && id < soundTracks.length)
         {
            try
            {
               switch (id)
               {
                  case SOUND_BGMUSIC:
                        soundData[id] = new Sound("/bgmusic.mmf");
                     break;
               }
               if(soundData[id] != null)
               {
                  soundTracks[id] = soundPlayer.getTrack();
                  soundTracks[id].setSound(soundData[id]);
                  //soundTracks[id].setEventListener(this);
               }
            }
            catch (Exception ex)
            {
               ex.printStackTrace();
            }
            System.gc();
         }
      }

      public void soundUnload()
      {
         if(soundTracks != null)
         {
            for(int i = 0; i < soundTracks.length; i++) 
            {
               soundData[i] = null;
               soundTracks[i].stop();
               soundTracks[i].removeSound();
               soundTracks[i] = null;
            }
         }
         System.gc();
      }

      public static void soundPlay(byte id, int duration)
      {
         if(settings[SETTINGS_SOUND] == 1 && soundTracks != null && id >= 0 && id < soundTracks.length)
         {
            switch(soundTracks[id].getState() ){
               case SoundTrack.READY:
                     soundTracks[id].play(duration);
                  break;
               case SoundTrack.PAUSED:
                     soundTracks[id].resume();
                  break;
            }
         }
      }

      public static void soundStop(byte id)
      {
         if(soundTracks != null && id >= 0 && id < soundTracks.length)
         {
            switch(soundTracks[id].getState() ){
               case SoundTrack.PLAYING :
               case SoundTrack.PAUSED:
                     soundTracks[id].stop(); 
                  break;
            }
         }
      }

      public static void soundPause()
      {
         if(soundTracks != null)
         {
            for(int i = 0; i < soundTracks.length; i++)
            {
               if(soundTracks[i].getState() == SoundTrack.PLAYING)
               {
                  soundTracks[i].pause();
               }
            }
         }
      }

      public static void soundResume()
      {
         if(soundTracks != null)
         {
            for(int i = 0; i < soundTracks.length; i++)
            {
               if(soundTracks[i].getState() == SoundTrack.PAUSED)
               {
                  soundTracks[i].resume();
               }
            }
         }
      }
/*****************************************************************************************************************************/

   //#endif

   //#if sp
    public int top10AddNewScore(String UName,int Uscore) {
        int place = -1,i = 0;
        byte flag;

        if (top10count == 0) {
            flag = 1;
        }
        else {
            flag = 0;
        }
        for (i = 0; i < top10count; i++) {
            if (Uscore > top10Score[i]) {
                flag = 1;break;
            }
        }     
     
        if ((flag == 0) && (top10count < 10)) {
            flag = 1; 
            i = top10count;
        }
     
        if (flag == 1) {
            top10count++;
            if (top10count > 10) {
                top10count = 10;
            }

            place = i;
            for (i = top10count-1; i > place; i--) {
                top10Name[i] = top10Name[i-1]; 
                top10Score[i] = top10Score[i-1];
            }
            top10Name[place] = UName;
            top10Score[place] = Uscore;
        }

        top10WriteRMS();

        return place + 1;
    }

    public void top10WriteRMS() {
        int i;
        byte[] buff = null;

        try {
            rmsDelete(RMS_TOP10);
            baos = new ByteArrayOutputStream();
            out = new DataOutputStream(baos);
            out.writeInt(top10count);
            for (i = 0; i < top10count; i++) {
                out.writeUTF(top10Name[i].toString());
                out.writeInt(top10Score[i]);
            }
            buff = baos.toByteArray();
            rst = RecordStore.openRecordStore(RMS_TOP10, true);
            rst.addRecord(buff, 0, buff.length);
            rst.closeRecordStore();
            baos.close();
            out.close();
        }
        catch (Exception ex) { 
            ex.printStackTrace();
        }
        baos = null;
        out = null;
        buff = null;
        System.gc();
    }

    public void top10ReadRMS() {
        int i;
        if (top10Name != null && top10Score != null) {
            try {
                rst = RecordStore.openRecordStore(RMS_TOP10, false);
                if (rst != null) {
                    byte[] record = rst.getRecord(1);
                    din = new DataInputStream(new ByteArrayInputStream(record, 0, record.length));
                    top10count = din.readInt();
                    for (i = 0; i < top10count; i++) {
                        top10Name[i] = din.readUTF();
                        top10Score[i] = din.readInt();
                    }
                    din.close();
                }
                rst.closeRecordStore();
            }
            catch(Exception ex) {
                ex.printStackTrace();
            }
        }
        din = null;
        System.gc();
    }
//#endif
}

